~ubuntu-branches/ubuntu/precise/linux-ti-omap4/precise-security

« back to all changes in this revision

Viewing changes to net/batman-adv/translation-table.c

  • Committer: Package Import Robot
  • Author(s): Paolo Pisati, Paolo Pisati
  • Date: 2011-12-06 15:56:07 UTC
  • Revision ID: package-import@ubuntu.com-20111206155607-pcf44kv5fmhk564f
Tags: 3.2.0-1401.1
[ Paolo Pisati ]

* Rebased on top of Ubuntu-3.2.0-3.8
* Tilt-tracking @ ef2487af4bb15bdd0689631774b5a5e3a59f74e2
* Delete debian.ti-omap4/control, it shoudln't be tracked
* Fix architecture spelling (s/armel/armhf/)
* [Config] Update configs following 3.2 import
* [Config] Fix compilation: disable CODA and ARCH_OMAP3
* [Config] Fix compilation: disable Ethernet Faraday
* Update series to precise

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
#include "translation-table.h"
24
24
#include "soft-interface.h"
25
25
#include "hard-interface.h"
 
26
#include "send.h"
26
27
#include "hash.h"
27
28
#include "originator.h"
28
 
 
29
 
static void tt_local_purge(struct work_struct *work);
30
 
static void _tt_global_del_orig(struct bat_priv *bat_priv,
31
 
                                 struct tt_global_entry *tt_global_entry,
32
 
                                 char *message);
33
 
 
34
 
/* returns 1 if they are the same mac addr */
35
 
static int compare_ltt(struct hlist_node *node, void *data2)
36
 
{
37
 
        void *data1 = container_of(node, struct tt_local_entry, hash_entry);
38
 
 
39
 
        return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
40
 
}
41
 
 
42
 
/* returns 1 if they are the same mac addr */
43
 
static int compare_gtt(struct hlist_node *node, void *data2)
44
 
{
45
 
        void *data1 = container_of(node, struct tt_global_entry, hash_entry);
46
 
 
47
 
        return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
48
 
}
49
 
 
50
 
static void tt_local_start_timer(struct bat_priv *bat_priv)
51
 
{
52
 
        INIT_DELAYED_WORK(&bat_priv->tt_work, tt_local_purge);
53
 
        queue_delayed_work(bat_event_workqueue, &bat_priv->tt_work, 10 * HZ);
 
29
#include "routing.h"
 
30
 
 
31
#include <linux/crc16.h>
 
32
 
 
33
static void _tt_global_del(struct bat_priv *bat_priv,
 
34
                           struct tt_global_entry *tt_global_entry,
 
35
                           const char *message);
 
36
static void tt_purge(struct work_struct *work);
 
37
 
 
38
/* returns 1 if they are the same mac addr */
 
39
static int compare_ltt(const struct hlist_node *node, const void *data2)
 
40
{
 
41
        const void *data1 = container_of(node, struct tt_local_entry,
 
42
                                         hash_entry);
 
43
 
 
44
        return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
 
45
}
 
46
 
 
47
/* returns 1 if they are the same mac addr */
 
48
static int compare_gtt(const struct hlist_node *node, const void *data2)
 
49
{
 
50
        const void *data1 = container_of(node, struct tt_global_entry,
 
51
                                         hash_entry);
 
52
 
 
53
        return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
 
54
}
 
55
 
 
56
static void tt_start_timer(struct bat_priv *bat_priv)
 
57
{
 
58
        INIT_DELAYED_WORK(&bat_priv->tt_work, tt_purge);
 
59
        queue_delayed_work(bat_event_workqueue, &bat_priv->tt_work,
 
60
                           msecs_to_jiffies(5000));
54
61
}
55
62
 
56
63
static struct tt_local_entry *tt_local_hash_find(struct bat_priv *bat_priv,
57
 
                                                   void *data)
 
64
                                                 const void *data)
58
65
{
59
66
        struct hashtable_t *hash = bat_priv->tt_local_hash;
60
67
        struct hlist_head *head;
73
80
                if (!compare_eth(tt_local_entry, data))
74
81
                        continue;
75
82
 
 
83
                if (!atomic_inc_not_zero(&tt_local_entry->refcount))
 
84
                        continue;
 
85
 
76
86
                tt_local_entry_tmp = tt_local_entry;
77
87
                break;
78
88
        }
82
92
}
83
93
 
84
94
static struct tt_global_entry *tt_global_hash_find(struct bat_priv *bat_priv,
85
 
                                                     void *data)
 
95
                                                   const void *data)
86
96
{
87
97
        struct hashtable_t *hash = bat_priv->tt_global_hash;
88
98
        struct hlist_head *head;
102
112
                if (!compare_eth(tt_global_entry, data))
103
113
                        continue;
104
114
 
 
115
                if (!atomic_inc_not_zero(&tt_global_entry->refcount))
 
116
                        continue;
 
117
 
105
118
                tt_global_entry_tmp = tt_global_entry;
106
119
                break;
107
120
        }
110
123
        return tt_global_entry_tmp;
111
124
}
112
125
 
113
 
int tt_local_init(struct bat_priv *bat_priv)
 
126
static bool is_out_of_time(unsigned long starting_time, unsigned long timeout)
 
127
{
 
128
        unsigned long deadline;
 
129
        deadline = starting_time + msecs_to_jiffies(timeout);
 
130
 
 
131
        return time_after(jiffies, deadline);
 
132
}
 
133
 
 
134
static void tt_local_entry_free_ref(struct tt_local_entry *tt_local_entry)
 
135
{
 
136
        if (atomic_dec_and_test(&tt_local_entry->refcount))
 
137
                kfree_rcu(tt_local_entry, rcu);
 
138
}
 
139
 
 
140
static void tt_global_entry_free_rcu(struct rcu_head *rcu)
 
141
{
 
142
        struct tt_global_entry *tt_global_entry;
 
143
 
 
144
        tt_global_entry = container_of(rcu, struct tt_global_entry, rcu);
 
145
 
 
146
        if (tt_global_entry->orig_node)
 
147
                orig_node_free_ref(tt_global_entry->orig_node);
 
148
 
 
149
        kfree(tt_global_entry);
 
150
}
 
151
 
 
152
static void tt_global_entry_free_ref(struct tt_global_entry *tt_global_entry)
 
153
{
 
154
        if (atomic_dec_and_test(&tt_global_entry->refcount))
 
155
                call_rcu(&tt_global_entry->rcu, tt_global_entry_free_rcu);
 
156
}
 
157
 
 
158
static void tt_local_event(struct bat_priv *bat_priv, const uint8_t *addr,
 
159
                           uint8_t flags)
 
160
{
 
161
        struct tt_change_node *tt_change_node;
 
162
 
 
163
        tt_change_node = kmalloc(sizeof(*tt_change_node), GFP_ATOMIC);
 
164
 
 
165
        if (!tt_change_node)
 
166
                return;
 
167
 
 
168
        tt_change_node->change.flags = flags;
 
169
        memcpy(tt_change_node->change.addr, addr, ETH_ALEN);
 
170
 
 
171
        spin_lock_bh(&bat_priv->tt_changes_list_lock);
 
172
        /* track the change in the OGMinterval list */
 
173
        list_add_tail(&tt_change_node->list, &bat_priv->tt_changes_list);
 
174
        atomic_inc(&bat_priv->tt_local_changes);
 
175
        spin_unlock_bh(&bat_priv->tt_changes_list_lock);
 
176
 
 
177
        atomic_set(&bat_priv->tt_ogm_append_cnt, 0);
 
178
}
 
179
 
 
180
int tt_len(int changes_num)
 
181
{
 
182
        return changes_num * sizeof(struct tt_change);
 
183
}
 
184
 
 
185
static int tt_local_init(struct bat_priv *bat_priv)
114
186
{
115
187
        if (bat_priv->tt_local_hash)
116
188
                return 1;
120
192
        if (!bat_priv->tt_local_hash)
121
193
                return 0;
122
194
 
123
 
        atomic_set(&bat_priv->tt_local_changed, 0);
124
 
        tt_local_start_timer(bat_priv);
125
 
 
126
195
        return 1;
127
196
}
128
197
 
129
 
void tt_local_add(struct net_device *soft_iface, uint8_t *addr)
 
198
void tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
 
199
                  int ifindex)
130
200
{
131
201
        struct bat_priv *bat_priv = netdev_priv(soft_iface);
132
 
        struct tt_local_entry *tt_local_entry;
133
 
        struct tt_global_entry *tt_global_entry;
134
 
        int required_bytes;
 
202
        struct tt_local_entry *tt_local_entry = NULL;
 
203
        struct tt_global_entry *tt_global_entry = NULL;
135
204
 
136
 
        spin_lock_bh(&bat_priv->tt_lhash_lock);
137
205
        tt_local_entry = tt_local_hash_find(bat_priv, addr);
138
 
        spin_unlock_bh(&bat_priv->tt_lhash_lock);
139
206
 
140
207
        if (tt_local_entry) {
141
208
                tt_local_entry->last_seen = jiffies;
142
 
                return;
143
 
        }
144
 
 
145
 
        /* only announce as many hosts as possible in the batman-packet and
146
 
           space in batman_packet->num_tt That also should give a limit to
147
 
           MAC-flooding. */
148
 
        required_bytes = (bat_priv->num_local_tt + 1) * ETH_ALEN;
149
 
        required_bytes += BAT_PACKET_LEN;
150
 
 
151
 
        if ((required_bytes > ETH_DATA_LEN) ||
152
 
            (atomic_read(&bat_priv->aggregated_ogms) &&
153
 
             required_bytes > MAX_AGGREGATION_BYTES) ||
154
 
            (bat_priv->num_local_tt + 1 > 255)) {
155
 
                bat_dbg(DBG_ROUTES, bat_priv,
156
 
                        "Can't add new local tt entry (%pM): "
157
 
                        "number of local tt entries exceeds packet size\n",
158
 
                        addr);
159
 
                return;
160
 
        }
161
 
 
162
 
        bat_dbg(DBG_ROUTES, bat_priv,
163
 
                "Creating new local tt entry: %pM\n", addr);
164
 
 
165
 
        tt_local_entry = kmalloc(sizeof(struct tt_local_entry), GFP_ATOMIC);
 
209
                goto out;
 
210
        }
 
211
 
 
212
        tt_local_entry = kmalloc(sizeof(*tt_local_entry), GFP_ATOMIC);
166
213
        if (!tt_local_entry)
167
 
                return;
 
214
                goto out;
 
215
 
 
216
        bat_dbg(DBG_TT, bat_priv,
 
217
                "Creating new local tt entry: %pM (ttvn: %d)\n", addr,
 
218
                (uint8_t)atomic_read(&bat_priv->ttvn));
168
219
 
169
220
        memcpy(tt_local_entry->addr, addr, ETH_ALEN);
170
221
        tt_local_entry->last_seen = jiffies;
 
222
        tt_local_entry->flags = NO_FLAGS;
 
223
        if (is_wifi_iface(ifindex))
 
224
                tt_local_entry->flags |= TT_CLIENT_WIFI;
 
225
        atomic_set(&tt_local_entry->refcount, 2);
171
226
 
172
227
        /* the batman interface mac address should never be purged */
173
228
        if (compare_eth(addr, soft_iface->dev_addr))
174
 
                tt_local_entry->never_purge = 1;
175
 
        else
176
 
                tt_local_entry->never_purge = 0;
177
 
 
178
 
        spin_lock_bh(&bat_priv->tt_lhash_lock);
 
229
                tt_local_entry->flags |= TT_CLIENT_NOPURGE;
 
230
 
 
231
        tt_local_event(bat_priv, addr, tt_local_entry->flags);
 
232
 
 
233
        /* The local entry has to be marked as NEW to avoid to send it in
 
234
         * a full table response going out before the next ttvn increment
 
235
         * (consistency check) */
 
236
        tt_local_entry->flags |= TT_CLIENT_NEW;
179
237
 
180
238
        hash_add(bat_priv->tt_local_hash, compare_ltt, choose_orig,
181
239
                 tt_local_entry, &tt_local_entry->hash_entry);
182
 
        bat_priv->num_local_tt++;
183
 
        atomic_set(&bat_priv->tt_local_changed, 1);
184
 
 
185
 
        spin_unlock_bh(&bat_priv->tt_lhash_lock);
186
240
 
187
241
        /* remove address from global hash if present */
188
 
        spin_lock_bh(&bat_priv->tt_ghash_lock);
189
 
 
190
242
        tt_global_entry = tt_global_hash_find(bat_priv, addr);
191
243
 
 
244
        /* Check whether it is a roaming! */
 
245
        if (tt_global_entry) {
 
246
                /* This node is probably going to update its tt table */
 
247
                tt_global_entry->orig_node->tt_poss_change = true;
 
248
                /* The global entry has to be marked as PENDING and has to be
 
249
                 * kept for consistency purpose */
 
250
                tt_global_entry->flags |= TT_CLIENT_PENDING;
 
251
                send_roam_adv(bat_priv, tt_global_entry->addr,
 
252
                              tt_global_entry->orig_node);
 
253
        }
 
254
out:
 
255
        if (tt_local_entry)
 
256
                tt_local_entry_free_ref(tt_local_entry);
192
257
        if (tt_global_entry)
193
 
                _tt_global_del_orig(bat_priv, tt_global_entry,
194
 
                                     "local tt received");
195
 
 
196
 
        spin_unlock_bh(&bat_priv->tt_ghash_lock);
 
258
                tt_global_entry_free_ref(tt_global_entry);
197
259
}
198
260
 
199
 
int tt_local_fill_buffer(struct bat_priv *bat_priv,
200
 
                          unsigned char *buff, int buff_len)
 
261
int tt_changes_fill_buffer(struct bat_priv *bat_priv,
 
262
                           unsigned char *buff, int buff_len)
201
263
{
202
 
        struct hashtable_t *hash = bat_priv->tt_local_hash;
203
 
        struct tt_local_entry *tt_local_entry;
204
 
        struct hlist_node *node;
205
 
        struct hlist_head *head;
206
 
        int i, count = 0;
207
 
 
208
 
        spin_lock_bh(&bat_priv->tt_lhash_lock);
209
 
 
210
 
        for (i = 0; i < hash->size; i++) {
211
 
                head = &hash->table[i];
212
 
 
213
 
                rcu_read_lock();
214
 
                hlist_for_each_entry_rcu(tt_local_entry, node,
215
 
                                         head, hash_entry) {
216
 
                        if (buff_len < (count + 1) * ETH_ALEN)
217
 
                                break;
218
 
 
219
 
                        memcpy(buff + (count * ETH_ALEN), tt_local_entry->addr,
220
 
                               ETH_ALEN);
221
 
 
 
264
        int count = 0, tot_changes = 0;
 
265
        struct tt_change_node *entry, *safe;
 
266
 
 
267
        if (buff_len > 0)
 
268
                tot_changes = buff_len / tt_len(1);
 
269
 
 
270
        spin_lock_bh(&bat_priv->tt_changes_list_lock);
 
271
        atomic_set(&bat_priv->tt_local_changes, 0);
 
272
 
 
273
        list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list,
 
274
                        list) {
 
275
                if (count < tot_changes) {
 
276
                        memcpy(buff + tt_len(count),
 
277
                               &entry->change, sizeof(struct tt_change));
222
278
                        count++;
223
279
                }
224
 
                rcu_read_unlock();
225
 
        }
226
 
 
227
 
        /* if we did not get all new local tts see you next time  ;-) */
228
 
        if (count == bat_priv->num_local_tt)
229
 
                atomic_set(&bat_priv->tt_local_changed, 0);
230
 
 
231
 
        spin_unlock_bh(&bat_priv->tt_lhash_lock);
232
 
        return count;
 
280
                list_del(&entry->list);
 
281
                kfree(entry);
 
282
        }
 
283
        spin_unlock_bh(&bat_priv->tt_changes_list_lock);
 
284
 
 
285
        /* Keep the buffer for possible tt_request */
 
286
        spin_lock_bh(&bat_priv->tt_buff_lock);
 
287
        kfree(bat_priv->tt_buff);
 
288
        bat_priv->tt_buff_len = 0;
 
289
        bat_priv->tt_buff = NULL;
 
290
        /* We check whether this new OGM has no changes due to size
 
291
         * problems */
 
292
        if (buff_len > 0) {
 
293
                /**
 
294
                 * if kmalloc() fails we will reply with the full table
 
295
                 * instead of providing the diff
 
296
                 */
 
297
                bat_priv->tt_buff = kmalloc(buff_len, GFP_ATOMIC);
 
298
                if (bat_priv->tt_buff) {
 
299
                        memcpy(bat_priv->tt_buff, buff, buff_len);
 
300
                        bat_priv->tt_buff_len = buff_len;
 
301
                }
 
302
        }
 
303
        spin_unlock_bh(&bat_priv->tt_buff_lock);
 
304
 
 
305
        return tot_changes;
233
306
}
234
307
 
235
308
int tt_local_seq_print_text(struct seq_file *seq, void *offset)
261
334
        }
262
335
 
263
336
        seq_printf(seq, "Locally retrieved addresses (from %s) "
264
 
                   "announced via TT:\n",
265
 
                   net_dev->name);
266
 
 
267
 
        spin_lock_bh(&bat_priv->tt_lhash_lock);
 
337
                   "announced via TT (TTVN: %u):\n",
 
338
                   net_dev->name, (uint8_t)atomic_read(&bat_priv->ttvn));
268
339
 
269
340
        buf_size = 1;
270
341
        /* Estimate length for: " * xx:xx:xx:xx:xx:xx\n" */
273
344
 
274
345
                rcu_read_lock();
275
346
                __hlist_for_each_rcu(node, head)
276
 
                        buf_size += 21;
 
347
                        buf_size += 29;
277
348
                rcu_read_unlock();
278
349
        }
279
350
 
280
351
        buff = kmalloc(buf_size, GFP_ATOMIC);
281
352
        if (!buff) {
282
 
                spin_unlock_bh(&bat_priv->tt_lhash_lock);
283
353
                ret = -ENOMEM;
284
354
                goto out;
285
355
        }
293
363
                rcu_read_lock();
294
364
                hlist_for_each_entry_rcu(tt_local_entry, node,
295
365
                                         head, hash_entry) {
296
 
                        pos += snprintf(buff + pos, 22, " * %pM\n",
297
 
                                        tt_local_entry->addr);
 
366
                        pos += snprintf(buff + pos, 30, " * %pM "
 
367
                                        "[%c%c%c%c%c]\n",
 
368
                                        tt_local_entry->addr,
 
369
                                        (tt_local_entry->flags &
 
370
                                         TT_CLIENT_ROAM ? 'R' : '.'),
 
371
                                        (tt_local_entry->flags &
 
372
                                         TT_CLIENT_NOPURGE ? 'P' : '.'),
 
373
                                        (tt_local_entry->flags &
 
374
                                         TT_CLIENT_NEW ? 'N' : '.'),
 
375
                                        (tt_local_entry->flags &
 
376
                                         TT_CLIENT_PENDING ? 'X' : '.'),
 
377
                                        (tt_local_entry->flags &
 
378
                                         TT_CLIENT_WIFI ? 'W' : '.'));
298
379
                }
299
380
                rcu_read_unlock();
300
381
        }
301
382
 
302
 
        spin_unlock_bh(&bat_priv->tt_lhash_lock);
303
 
 
304
383
        seq_printf(seq, "%s", buff);
305
384
        kfree(buff);
306
385
out:
309
388
        return ret;
310
389
}
311
390
 
312
 
static void _tt_local_del(struct hlist_node *node, void *arg)
313
 
{
314
 
        struct bat_priv *bat_priv = (struct bat_priv *)arg;
315
 
        void *data = container_of(node, struct tt_local_entry, hash_entry);
316
 
 
317
 
        kfree(data);
318
 
        bat_priv->num_local_tt--;
319
 
        atomic_set(&bat_priv->tt_local_changed, 1);
320
 
}
321
 
 
322
 
static void tt_local_del(struct bat_priv *bat_priv,
323
 
                          struct tt_local_entry *tt_local_entry,
324
 
                          char *message)
325
 
{
326
 
        bat_dbg(DBG_ROUTES, bat_priv, "Deleting local tt entry (%pM): %s\n",
327
 
                tt_local_entry->addr, message);
328
 
 
329
 
        hash_remove(bat_priv->tt_local_hash, compare_ltt, choose_orig,
330
 
                    tt_local_entry->addr);
331
 
        _tt_local_del(&tt_local_entry->hash_entry, bat_priv);
332
 
}
333
 
 
334
 
void tt_local_remove(struct bat_priv *bat_priv,
335
 
                      uint8_t *addr, char *message)
336
 
{
337
 
        struct tt_local_entry *tt_local_entry;
338
 
 
339
 
        spin_lock_bh(&bat_priv->tt_lhash_lock);
 
391
static void tt_local_set_pending(struct bat_priv *bat_priv,
 
392
                                 struct tt_local_entry *tt_local_entry,
 
393
                                 uint16_t flags)
 
394
{
 
395
        tt_local_event(bat_priv, tt_local_entry->addr,
 
396
                       tt_local_entry->flags | flags);
 
397
 
 
398
        /* The local client has to be marked as "pending to be removed" but has
 
399
         * to be kept in the table in order to send it in a full table
 
400
         * response issued before the net ttvn increment (consistency check) */
 
401
        tt_local_entry->flags |= TT_CLIENT_PENDING;
 
402
}
 
403
 
 
404
void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr,
 
405
                     const char *message, bool roaming)
 
406
{
 
407
        struct tt_local_entry *tt_local_entry = NULL;
340
408
 
341
409
        tt_local_entry = tt_local_hash_find(bat_priv, addr);
342
 
 
 
410
        if (!tt_local_entry)
 
411
                goto out;
 
412
 
 
413
        tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL |
 
414
                             (roaming ? TT_CLIENT_ROAM : NO_FLAGS));
 
415
 
 
416
        bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) pending to be removed: "
 
417
                "%s\n", tt_local_entry->addr, message);
 
418
out:
343
419
        if (tt_local_entry)
344
 
                tt_local_del(bat_priv, tt_local_entry, message);
345
 
 
346
 
        spin_unlock_bh(&bat_priv->tt_lhash_lock);
 
420
                tt_local_entry_free_ref(tt_local_entry);
347
421
}
348
422
 
349
 
static void tt_local_purge(struct work_struct *work)
 
423
static void tt_local_purge(struct bat_priv *bat_priv)
350
424
{
351
 
        struct delayed_work *delayed_work =
352
 
                container_of(work, struct delayed_work, work);
353
 
        struct bat_priv *bat_priv =
354
 
                container_of(delayed_work, struct bat_priv, tt_work);
355
425
        struct hashtable_t *hash = bat_priv->tt_local_hash;
356
426
        struct tt_local_entry *tt_local_entry;
357
427
        struct hlist_node *node, *node_tmp;
358
428
        struct hlist_head *head;
359
 
        unsigned long timeout;
 
429
        spinlock_t *list_lock; /* protects write access to the hash lists */
360
430
        int i;
361
431
 
362
 
        spin_lock_bh(&bat_priv->tt_lhash_lock);
363
 
 
364
432
        for (i = 0; i < hash->size; i++) {
365
433
                head = &hash->table[i];
 
434
                list_lock = &hash->list_locks[i];
366
435
 
 
436
                spin_lock_bh(list_lock);
367
437
                hlist_for_each_entry_safe(tt_local_entry, node, node_tmp,
368
438
                                          head, hash_entry) {
369
 
                        if (tt_local_entry->never_purge)
370
 
                                continue;
371
 
 
372
 
                        timeout = tt_local_entry->last_seen;
373
 
                        timeout += TT_LOCAL_TIMEOUT * HZ;
374
 
 
375
 
                        if (time_before(jiffies, timeout))
376
 
                                continue;
377
 
 
378
 
                        tt_local_del(bat_priv, tt_local_entry,
379
 
                                      "address timed out");
 
439
                        if (tt_local_entry->flags & TT_CLIENT_NOPURGE)
 
440
                                continue;
 
441
 
 
442
                        /* entry already marked for deletion */
 
443
                        if (tt_local_entry->flags & TT_CLIENT_PENDING)
 
444
                                continue;
 
445
 
 
446
                        if (!is_out_of_time(tt_local_entry->last_seen,
 
447
                                            TT_LOCAL_TIMEOUT * 1000))
 
448
                                continue;
 
449
 
 
450
                        tt_local_set_pending(bat_priv, tt_local_entry,
 
451
                                             TT_CLIENT_DEL);
 
452
                        bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) "
 
453
                                "pending to be removed: timed out\n",
 
454
                                tt_local_entry->addr);
380
455
                }
 
456
                spin_unlock_bh(list_lock);
381
457
        }
382
458
 
383
 
        spin_unlock_bh(&bat_priv->tt_lhash_lock);
384
 
        tt_local_start_timer(bat_priv);
385
459
}
386
460
 
387
 
void tt_local_free(struct bat_priv *bat_priv)
 
461
static void tt_local_table_free(struct bat_priv *bat_priv)
388
462
{
 
463
        struct hashtable_t *hash;
 
464
        spinlock_t *list_lock; /* protects write access to the hash lists */
 
465
        struct tt_local_entry *tt_local_entry;
 
466
        struct hlist_node *node, *node_tmp;
 
467
        struct hlist_head *head;
 
468
        int i;
 
469
 
389
470
        if (!bat_priv->tt_local_hash)
390
471
                return;
391
472
 
392
 
        cancel_delayed_work_sync(&bat_priv->tt_work);
393
 
        hash_delete(bat_priv->tt_local_hash, _tt_local_del, bat_priv);
 
473
        hash = bat_priv->tt_local_hash;
 
474
 
 
475
        for (i = 0; i < hash->size; i++) {
 
476
                head = &hash->table[i];
 
477
                list_lock = &hash->list_locks[i];
 
478
 
 
479
                spin_lock_bh(list_lock);
 
480
                hlist_for_each_entry_safe(tt_local_entry, node, node_tmp,
 
481
                                          head, hash_entry) {
 
482
                        hlist_del_rcu(node);
 
483
                        tt_local_entry_free_ref(tt_local_entry);
 
484
                }
 
485
                spin_unlock_bh(list_lock);
 
486
        }
 
487
 
 
488
        hash_destroy(hash);
 
489
 
394
490
        bat_priv->tt_local_hash = NULL;
395
491
}
396
492
 
397
 
int tt_global_init(struct bat_priv *bat_priv)
 
493
static int tt_global_init(struct bat_priv *bat_priv)
398
494
{
399
495
        if (bat_priv->tt_global_hash)
400
496
                return 1;
407
503
        return 1;
408
504
}
409
505
 
410
 
void tt_global_add_orig(struct bat_priv *bat_priv,
411
 
                         struct orig_node *orig_node,
412
 
                         unsigned char *tt_buff, int tt_buff_len)
 
506
static void tt_changes_list_free(struct bat_priv *bat_priv)
 
507
{
 
508
        struct tt_change_node *entry, *safe;
 
509
 
 
510
        spin_lock_bh(&bat_priv->tt_changes_list_lock);
 
511
 
 
512
        list_for_each_entry_safe(entry, safe, &bat_priv->tt_changes_list,
 
513
                                 list) {
 
514
                list_del(&entry->list);
 
515
                kfree(entry);
 
516
        }
 
517
 
 
518
        atomic_set(&bat_priv->tt_local_changes, 0);
 
519
        spin_unlock_bh(&bat_priv->tt_changes_list_lock);
 
520
}
 
521
 
 
522
/* caller must hold orig_node refcount */
 
523
int tt_global_add(struct bat_priv *bat_priv, struct orig_node *orig_node,
 
524
                  const unsigned char *tt_addr, uint8_t ttvn, bool roaming,
 
525
                  bool wifi)
413
526
{
414
527
        struct tt_global_entry *tt_global_entry;
415
 
        struct tt_local_entry *tt_local_entry;
416
 
        int tt_buff_count = 0;
417
 
        unsigned char *tt_ptr;
418
 
 
419
 
        while ((tt_buff_count + 1) * ETH_ALEN <= tt_buff_len) {
420
 
                spin_lock_bh(&bat_priv->tt_ghash_lock);
421
 
 
422
 
                tt_ptr = tt_buff + (tt_buff_count * ETH_ALEN);
423
 
                tt_global_entry = tt_global_hash_find(bat_priv, tt_ptr);
424
 
 
425
 
                if (!tt_global_entry) {
426
 
                        spin_unlock_bh(&bat_priv->tt_ghash_lock);
427
 
 
428
 
                        tt_global_entry =
429
 
                                kmalloc(sizeof(struct tt_global_entry),
430
 
                                        GFP_ATOMIC);
431
 
 
432
 
                        if (!tt_global_entry)
433
 
                                break;
434
 
 
435
 
                        memcpy(tt_global_entry->addr, tt_ptr, ETH_ALEN);
436
 
 
437
 
                        bat_dbg(DBG_ROUTES, bat_priv,
438
 
                                "Creating new global tt entry: "
439
 
                                "%pM (via %pM)\n",
440
 
                                tt_global_entry->addr, orig_node->orig);
441
 
 
442
 
                        spin_lock_bh(&bat_priv->tt_ghash_lock);
443
 
                        hash_add(bat_priv->tt_global_hash, compare_gtt,
444
 
                                 choose_orig, tt_global_entry,
445
 
                                 &tt_global_entry->hash_entry);
446
 
 
447
 
                }
448
 
 
 
528
        struct orig_node *orig_node_tmp;
 
529
        int ret = 0;
 
530
 
 
531
        tt_global_entry = tt_global_hash_find(bat_priv, tt_addr);
 
532
 
 
533
        if (!tt_global_entry) {
 
534
                tt_global_entry =
 
535
                        kmalloc(sizeof(*tt_global_entry),
 
536
                                GFP_ATOMIC);
 
537
                if (!tt_global_entry)
 
538
                        goto out;
 
539
 
 
540
                memcpy(tt_global_entry->addr, tt_addr, ETH_ALEN);
 
541
                /* Assign the new orig_node */
 
542
                atomic_inc(&orig_node->refcount);
449
543
                tt_global_entry->orig_node = orig_node;
450
 
                spin_unlock_bh(&bat_priv->tt_ghash_lock);
451
 
 
452
 
                /* remove address from local hash if present */
453
 
                spin_lock_bh(&bat_priv->tt_lhash_lock);
454
 
 
455
 
                tt_ptr = tt_buff + (tt_buff_count * ETH_ALEN);
456
 
                tt_local_entry = tt_local_hash_find(bat_priv, tt_ptr);
457
 
 
458
 
                if (tt_local_entry)
459
 
                        tt_local_del(bat_priv, tt_local_entry,
460
 
                                      "global tt received");
461
 
 
462
 
                spin_unlock_bh(&bat_priv->tt_lhash_lock);
463
 
 
464
 
                tt_buff_count++;
465
 
        }
466
 
 
467
 
        /* initialize, and overwrite if malloc succeeds */
468
 
        orig_node->tt_buff = NULL;
469
 
        orig_node->tt_buff_len = 0;
470
 
 
471
 
        if (tt_buff_len > 0) {
472
 
                orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC);
473
 
                if (orig_node->tt_buff) {
474
 
                        memcpy(orig_node->tt_buff, tt_buff, tt_buff_len);
475
 
                        orig_node->tt_buff_len = tt_buff_len;
 
544
                tt_global_entry->ttvn = ttvn;
 
545
                tt_global_entry->flags = NO_FLAGS;
 
546
                tt_global_entry->roam_at = 0;
 
547
                atomic_set(&tt_global_entry->refcount, 2);
 
548
 
 
549
                hash_add(bat_priv->tt_global_hash, compare_gtt,
 
550
                         choose_orig, tt_global_entry,
 
551
                         &tt_global_entry->hash_entry);
 
552
                atomic_inc(&orig_node->tt_size);
 
553
        } else {
 
554
                if (tt_global_entry->orig_node != orig_node) {
 
555
                        atomic_dec(&tt_global_entry->orig_node->tt_size);
 
556
                        orig_node_tmp = tt_global_entry->orig_node;
 
557
                        atomic_inc(&orig_node->refcount);
 
558
                        tt_global_entry->orig_node = orig_node;
 
559
                        orig_node_free_ref(orig_node_tmp);
 
560
                        atomic_inc(&orig_node->tt_size);
476
561
                }
 
562
                tt_global_entry->ttvn = ttvn;
 
563
                tt_global_entry->flags = NO_FLAGS;
 
564
                tt_global_entry->roam_at = 0;
477
565
        }
 
566
 
 
567
        if (wifi)
 
568
                tt_global_entry->flags |= TT_CLIENT_WIFI;
 
569
 
 
570
        bat_dbg(DBG_TT, bat_priv,
 
571
                "Creating new global tt entry: %pM (via %pM)\n",
 
572
                tt_global_entry->addr, orig_node->orig);
 
573
 
 
574
        /* remove address from local hash if present */
 
575
        tt_local_remove(bat_priv, tt_global_entry->addr,
 
576
                        "global tt received", roaming);
 
577
        ret = 1;
 
578
out:
 
579
        if (tt_global_entry)
 
580
                tt_global_entry_free_ref(tt_global_entry);
 
581
        return ret;
478
582
}
479
583
 
480
584
int tt_global_seq_print_text(struct seq_file *seq, void *offset)
508
612
        seq_printf(seq,
509
613
                   "Globally announced TT entries received via the mesh %s\n",
510
614
                   net_dev->name);
511
 
 
512
 
        spin_lock_bh(&bat_priv->tt_ghash_lock);
 
615
        seq_printf(seq, "       %-13s %s       %-15s %s %s\n",
 
616
                   "Client", "(TTVN)", "Originator", "(Curr TTVN)", "Flags");
513
617
 
514
618
        buf_size = 1;
515
 
        /* Estimate length for: " * xx:xx:xx:xx:xx:xx via xx:xx:xx:xx:xx:xx\n"*/
 
619
        /* Estimate length for: " * xx:xx:xx:xx:xx:xx (ttvn) via
 
620
         * xx:xx:xx:xx:xx:xx (cur_ttvn)\n"*/
516
621
        for (i = 0; i < hash->size; i++) {
517
622
                head = &hash->table[i];
518
623
 
519
624
                rcu_read_lock();
520
625
                __hlist_for_each_rcu(node, head)
521
 
                        buf_size += 43;
 
626
                        buf_size += 67;
522
627
                rcu_read_unlock();
523
628
        }
524
629
 
525
630
        buff = kmalloc(buf_size, GFP_ATOMIC);
526
631
        if (!buff) {
527
 
                spin_unlock_bh(&bat_priv->tt_ghash_lock);
528
632
                ret = -ENOMEM;
529
633
                goto out;
530
634
        }
 
635
 
531
636
        buff[0] = '\0';
532
637
        pos = 0;
533
638
 
537
642
                rcu_read_lock();
538
643
                hlist_for_each_entry_rcu(tt_global_entry, node,
539
644
                                         head, hash_entry) {
540
 
                        pos += snprintf(buff + pos, 44,
541
 
                                        " * %pM via %pM\n",
542
 
                                        tt_global_entry->addr,
543
 
                                        tt_global_entry->orig_node->orig);
 
645
                        pos += snprintf(buff + pos, 69,
 
646
                                        " * %pM  (%3u) via %pM     (%3u)   "
 
647
                                        "[%c%c%c]\n", tt_global_entry->addr,
 
648
                                        tt_global_entry->ttvn,
 
649
                                        tt_global_entry->orig_node->orig,
 
650
                                        (uint8_t) atomic_read(
 
651
                                                &tt_global_entry->orig_node->
 
652
                                                last_ttvn),
 
653
                                        (tt_global_entry->flags &
 
654
                                         TT_CLIENT_ROAM ? 'R' : '.'),
 
655
                                        (tt_global_entry->flags &
 
656
                                         TT_CLIENT_PENDING ? 'X' : '.'),
 
657
                                        (tt_global_entry->flags &
 
658
                                         TT_CLIENT_WIFI ? 'W' : '.'));
544
659
                }
545
660
                rcu_read_unlock();
546
661
        }
547
662
 
548
 
        spin_unlock_bh(&bat_priv->tt_ghash_lock);
549
 
 
550
663
        seq_printf(seq, "%s", buff);
551
664
        kfree(buff);
552
665
out:
555
668
        return ret;
556
669
}
557
670
 
558
 
static void _tt_global_del_orig(struct bat_priv *bat_priv,
559
 
                                 struct tt_global_entry *tt_global_entry,
560
 
                                 char *message)
 
671
static void _tt_global_del(struct bat_priv *bat_priv,
 
672
                           struct tt_global_entry *tt_global_entry,
 
673
                           const char *message)
561
674
{
562
 
        bat_dbg(DBG_ROUTES, bat_priv,
 
675
        if (!tt_global_entry)
 
676
                goto out;
 
677
 
 
678
        bat_dbg(DBG_TT, bat_priv,
563
679
                "Deleting global tt entry %pM (via %pM): %s\n",
564
680
                tt_global_entry->addr, tt_global_entry->orig_node->orig,
565
681
                message);
566
682
 
 
683
        atomic_dec(&tt_global_entry->orig_node->tt_size);
 
684
 
567
685
        hash_remove(bat_priv->tt_global_hash, compare_gtt, choose_orig,
568
686
                    tt_global_entry->addr);
569
 
        kfree(tt_global_entry);
 
687
out:
 
688
        if (tt_global_entry)
 
689
                tt_global_entry_free_ref(tt_global_entry);
 
690
}
 
691
 
 
692
void tt_global_del(struct bat_priv *bat_priv,
 
693
                   struct orig_node *orig_node, const unsigned char *addr,
 
694
                   const char *message, bool roaming)
 
695
{
 
696
        struct tt_global_entry *tt_global_entry = NULL;
 
697
 
 
698
        tt_global_entry = tt_global_hash_find(bat_priv, addr);
 
699
        if (!tt_global_entry)
 
700
                goto out;
 
701
 
 
702
        if (tt_global_entry->orig_node == orig_node) {
 
703
                if (roaming) {
 
704
                        tt_global_entry->flags |= TT_CLIENT_ROAM;
 
705
                        tt_global_entry->roam_at = jiffies;
 
706
                        goto out;
 
707
                }
 
708
                _tt_global_del(bat_priv, tt_global_entry, message);
 
709
        }
 
710
out:
 
711
        if (tt_global_entry)
 
712
                tt_global_entry_free_ref(tt_global_entry);
570
713
}
571
714
 
572
715
void tt_global_del_orig(struct bat_priv *bat_priv,
573
 
                         struct orig_node *orig_node, char *message)
 
716
                        struct orig_node *orig_node, const char *message)
574
717
{
575
718
        struct tt_global_entry *tt_global_entry;
576
 
        int tt_buff_count = 0;
577
 
        unsigned char *tt_ptr;
 
719
        int i;
 
720
        struct hashtable_t *hash = bat_priv->tt_global_hash;
 
721
        struct hlist_node *node, *safe;
 
722
        struct hlist_head *head;
 
723
        spinlock_t *list_lock; /* protects write access to the hash lists */
578
724
 
579
 
        if (orig_node->tt_buff_len == 0)
 
725
        if (!hash)
580
726
                return;
581
727
 
582
 
        spin_lock_bh(&bat_priv->tt_ghash_lock);
583
 
 
584
 
        while ((tt_buff_count + 1) * ETH_ALEN <= orig_node->tt_buff_len) {
585
 
                tt_ptr = orig_node->tt_buff + (tt_buff_count * ETH_ALEN);
586
 
                tt_global_entry = tt_global_hash_find(bat_priv, tt_ptr);
587
 
 
588
 
                if ((tt_global_entry) &&
589
 
                    (tt_global_entry->orig_node == orig_node))
590
 
                        _tt_global_del_orig(bat_priv, tt_global_entry,
591
 
                                             message);
592
 
 
593
 
                tt_buff_count++;
594
 
        }
595
 
 
596
 
        spin_unlock_bh(&bat_priv->tt_ghash_lock);
597
 
 
598
 
        orig_node->tt_buff_len = 0;
599
 
        kfree(orig_node->tt_buff);
600
 
        orig_node->tt_buff = NULL;
601
 
}
602
 
 
603
 
static void tt_global_del(struct hlist_node *node, void *arg)
604
 
{
605
 
        void *data = container_of(node, struct tt_global_entry, hash_entry);
606
 
 
607
 
        kfree(data);
608
 
}
609
 
 
610
 
void tt_global_free(struct bat_priv *bat_priv)
611
 
{
 
728
        for (i = 0; i < hash->size; i++) {
 
729
                head = &hash->table[i];
 
730
                list_lock = &hash->list_locks[i];
 
731
 
 
732
                spin_lock_bh(list_lock);
 
733
                hlist_for_each_entry_safe(tt_global_entry, node, safe,
 
734
                                         head, hash_entry) {
 
735
                        if (tt_global_entry->orig_node == orig_node) {
 
736
                                bat_dbg(DBG_TT, bat_priv,
 
737
                                        "Deleting global tt entry %pM "
 
738
                                        "(via %pM): originator time out\n",
 
739
                                        tt_global_entry->addr,
 
740
                                        tt_global_entry->orig_node->orig);
 
741
                                hlist_del_rcu(node);
 
742
                                tt_global_entry_free_ref(tt_global_entry);
 
743
                        }
 
744
                }
 
745
                spin_unlock_bh(list_lock);
 
746
        }
 
747
        atomic_set(&orig_node->tt_size, 0);
 
748
}
 
749
 
 
750
static void tt_global_roam_purge(struct bat_priv *bat_priv)
 
751
{
 
752
        struct hashtable_t *hash = bat_priv->tt_global_hash;
 
753
        struct tt_global_entry *tt_global_entry;
 
754
        struct hlist_node *node, *node_tmp;
 
755
        struct hlist_head *head;
 
756
        spinlock_t *list_lock; /* protects write access to the hash lists */
 
757
        int i;
 
758
 
 
759
        for (i = 0; i < hash->size; i++) {
 
760
                head = &hash->table[i];
 
761
                list_lock = &hash->list_locks[i];
 
762
 
 
763
                spin_lock_bh(list_lock);
 
764
                hlist_for_each_entry_safe(tt_global_entry, node, node_tmp,
 
765
                                          head, hash_entry) {
 
766
                        if (!(tt_global_entry->flags & TT_CLIENT_ROAM))
 
767
                                continue;
 
768
                        if (!is_out_of_time(tt_global_entry->roam_at,
 
769
                                            TT_CLIENT_ROAM_TIMEOUT * 1000))
 
770
                                continue;
 
771
 
 
772
                        bat_dbg(DBG_TT, bat_priv, "Deleting global "
 
773
                                "tt entry (%pM): Roaming timeout\n",
 
774
                                tt_global_entry->addr);
 
775
                        atomic_dec(&tt_global_entry->orig_node->tt_size);
 
776
                        hlist_del_rcu(node);
 
777
                        tt_global_entry_free_ref(tt_global_entry);
 
778
                }
 
779
                spin_unlock_bh(list_lock);
 
780
        }
 
781
 
 
782
}
 
783
 
 
784
static void tt_global_table_free(struct bat_priv *bat_priv)
 
785
{
 
786
        struct hashtable_t *hash;
 
787
        spinlock_t *list_lock; /* protects write access to the hash lists */
 
788
        struct tt_global_entry *tt_global_entry;
 
789
        struct hlist_node *node, *node_tmp;
 
790
        struct hlist_head *head;
 
791
        int i;
 
792
 
612
793
        if (!bat_priv->tt_global_hash)
613
794
                return;
614
795
 
615
 
        hash_delete(bat_priv->tt_global_hash, tt_global_del, NULL);
 
796
        hash = bat_priv->tt_global_hash;
 
797
 
 
798
        for (i = 0; i < hash->size; i++) {
 
799
                head = &hash->table[i];
 
800
                list_lock = &hash->list_locks[i];
 
801
 
 
802
                spin_lock_bh(list_lock);
 
803
                hlist_for_each_entry_safe(tt_global_entry, node, node_tmp,
 
804
                                          head, hash_entry) {
 
805
                        hlist_del_rcu(node);
 
806
                        tt_global_entry_free_ref(tt_global_entry);
 
807
                }
 
808
                spin_unlock_bh(list_lock);
 
809
        }
 
810
 
 
811
        hash_destroy(hash);
 
812
 
616
813
        bat_priv->tt_global_hash = NULL;
617
814
}
618
815
 
619
 
struct orig_node *transtable_search(struct bat_priv *bat_priv, uint8_t *addr)
620
 
{
621
 
        struct tt_global_entry *tt_global_entry;
 
816
static bool _is_ap_isolated(struct tt_local_entry *tt_local_entry,
 
817
                            struct tt_global_entry *tt_global_entry)
 
818
{
 
819
        bool ret = false;
 
820
 
 
821
        if (tt_local_entry->flags & TT_CLIENT_WIFI &&
 
822
            tt_global_entry->flags & TT_CLIENT_WIFI)
 
823
                ret = true;
 
824
 
 
825
        return ret;
 
826
}
 
827
 
 
828
struct orig_node *transtable_search(struct bat_priv *bat_priv,
 
829
                                    const uint8_t *src, const uint8_t *addr)
 
830
{
 
831
        struct tt_local_entry *tt_local_entry = NULL;
 
832
        struct tt_global_entry *tt_global_entry = NULL;
622
833
        struct orig_node *orig_node = NULL;
623
834
 
624
 
        spin_lock_bh(&bat_priv->tt_ghash_lock);
 
835
        if (src && atomic_read(&bat_priv->ap_isolation)) {
 
836
                tt_local_entry = tt_local_hash_find(bat_priv, src);
 
837
                if (!tt_local_entry)
 
838
                        goto out;
 
839
        }
 
840
 
625
841
        tt_global_entry = tt_global_hash_find(bat_priv, addr);
626
 
 
627
842
        if (!tt_global_entry)
628
843
                goto out;
629
844
 
 
845
        /* check whether the clients should not communicate due to AP
 
846
         * isolation */
 
847
        if (tt_local_entry && _is_ap_isolated(tt_local_entry, tt_global_entry))
 
848
                goto out;
 
849
 
630
850
        if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount))
631
851
                goto out;
632
852
 
 
853
        /* A global client marked as PENDING has already moved from that
 
854
         * originator */
 
855
        if (tt_global_entry->flags & TT_CLIENT_PENDING)
 
856
                goto out;
 
857
 
633
858
        orig_node = tt_global_entry->orig_node;
634
859
 
635
860
out:
636
 
        spin_unlock_bh(&bat_priv->tt_ghash_lock);
 
861
        if (tt_global_entry)
 
862
                tt_global_entry_free_ref(tt_global_entry);
 
863
        if (tt_local_entry)
 
864
                tt_local_entry_free_ref(tt_local_entry);
 
865
 
637
866
        return orig_node;
638
867
}
 
868
 
 
869
/* Calculates the checksum of the local table of a given orig_node */
 
870
uint16_t tt_global_crc(struct bat_priv *bat_priv, struct orig_node *orig_node)
 
871
{
 
872
        uint16_t total = 0, total_one;
 
873
        struct hashtable_t *hash = bat_priv->tt_global_hash;
 
874
        struct tt_global_entry *tt_global_entry;
 
875
        struct hlist_node *node;
 
876
        struct hlist_head *head;
 
877
        int i, j;
 
878
 
 
879
        for (i = 0; i < hash->size; i++) {
 
880
                head = &hash->table[i];
 
881
 
 
882
                rcu_read_lock();
 
883
                hlist_for_each_entry_rcu(tt_global_entry, node,
 
884
                                         head, hash_entry) {
 
885
                        if (compare_eth(tt_global_entry->orig_node,
 
886
                                        orig_node)) {
 
887
                                /* Roaming clients are in the global table for
 
888
                                 * consistency only. They don't have to be
 
889
                                 * taken into account while computing the
 
890
                                 * global crc */
 
891
                                if (tt_global_entry->flags & TT_CLIENT_ROAM)
 
892
                                        continue;
 
893
                                total_one = 0;
 
894
                                for (j = 0; j < ETH_ALEN; j++)
 
895
                                        total_one = crc16_byte(total_one,
 
896
                                                tt_global_entry->addr[j]);
 
897
                                total ^= total_one;
 
898
                        }
 
899
                }
 
900
                rcu_read_unlock();
 
901
        }
 
902
 
 
903
        return total;
 
904
}
 
905
 
 
906
/* Calculates the checksum of the local table */
 
907
uint16_t tt_local_crc(struct bat_priv *bat_priv)
 
908
{
 
909
        uint16_t total = 0, total_one;
 
910
        struct hashtable_t *hash = bat_priv->tt_local_hash;
 
911
        struct tt_local_entry *tt_local_entry;
 
912
        struct hlist_node *node;
 
913
        struct hlist_head *head;
 
914
        int i, j;
 
915
 
 
916
        for (i = 0; i < hash->size; i++) {
 
917
                head = &hash->table[i];
 
918
 
 
919
                rcu_read_lock();
 
920
                hlist_for_each_entry_rcu(tt_local_entry, node,
 
921
                                         head, hash_entry) {
 
922
                        /* not yet committed clients have not to be taken into
 
923
                         * account while computing the CRC */
 
924
                        if (tt_local_entry->flags & TT_CLIENT_NEW)
 
925
                                continue;
 
926
                        total_one = 0;
 
927
                        for (j = 0; j < ETH_ALEN; j++)
 
928
                                total_one = crc16_byte(total_one,
 
929
                                                   tt_local_entry->addr[j]);
 
930
                        total ^= total_one;
 
931
                }
 
932
                rcu_read_unlock();
 
933
        }
 
934
 
 
935
        return total;
 
936
}
 
937
 
 
938
static void tt_req_list_free(struct bat_priv *bat_priv)
 
939
{
 
940
        struct tt_req_node *node, *safe;
 
941
 
 
942
        spin_lock_bh(&bat_priv->tt_req_list_lock);
 
943
 
 
944
        list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
 
945
                list_del(&node->list);
 
946
                kfree(node);
 
947
        }
 
948
 
 
949
        spin_unlock_bh(&bat_priv->tt_req_list_lock);
 
950
}
 
951
 
 
952
void tt_save_orig_buffer(struct bat_priv *bat_priv, struct orig_node *orig_node,
 
953
                         const unsigned char *tt_buff, uint8_t tt_num_changes)
 
954
{
 
955
        uint16_t tt_buff_len = tt_len(tt_num_changes);
 
956
 
 
957
        /* Replace the old buffer only if I received something in the
 
958
         * last OGM (the OGM could carry no changes) */
 
959
        spin_lock_bh(&orig_node->tt_buff_lock);
 
960
        if (tt_buff_len > 0) {
 
961
                kfree(orig_node->tt_buff);
 
962
                orig_node->tt_buff_len = 0;
 
963
                orig_node->tt_buff = kmalloc(tt_buff_len, GFP_ATOMIC);
 
964
                if (orig_node->tt_buff) {
 
965
                        memcpy(orig_node->tt_buff, tt_buff, tt_buff_len);
 
966
                        orig_node->tt_buff_len = tt_buff_len;
 
967
                }
 
968
        }
 
969
        spin_unlock_bh(&orig_node->tt_buff_lock);
 
970
}
 
971
 
 
972
static void tt_req_purge(struct bat_priv *bat_priv)
 
973
{
 
974
        struct tt_req_node *node, *safe;
 
975
 
 
976
        spin_lock_bh(&bat_priv->tt_req_list_lock);
 
977
        list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
 
978
                if (is_out_of_time(node->issued_at,
 
979
                    TT_REQUEST_TIMEOUT * 1000)) {
 
980
                        list_del(&node->list);
 
981
                        kfree(node);
 
982
                }
 
983
        }
 
984
        spin_unlock_bh(&bat_priv->tt_req_list_lock);
 
985
}
 
986
 
 
987
/* returns the pointer to the new tt_req_node struct if no request
 
988
 * has already been issued for this orig_node, NULL otherwise */
 
989
static struct tt_req_node *new_tt_req_node(struct bat_priv *bat_priv,
 
990
                                          struct orig_node *orig_node)
 
991
{
 
992
        struct tt_req_node *tt_req_node_tmp, *tt_req_node = NULL;
 
993
 
 
994
        spin_lock_bh(&bat_priv->tt_req_list_lock);
 
995
        list_for_each_entry(tt_req_node_tmp, &bat_priv->tt_req_list, list) {
 
996
                if (compare_eth(tt_req_node_tmp, orig_node) &&
 
997
                    !is_out_of_time(tt_req_node_tmp->issued_at,
 
998
                                    TT_REQUEST_TIMEOUT * 1000))
 
999
                        goto unlock;
 
1000
        }
 
1001
 
 
1002
        tt_req_node = kmalloc(sizeof(*tt_req_node), GFP_ATOMIC);
 
1003
        if (!tt_req_node)
 
1004
                goto unlock;
 
1005
 
 
1006
        memcpy(tt_req_node->addr, orig_node->orig, ETH_ALEN);
 
1007
        tt_req_node->issued_at = jiffies;
 
1008
 
 
1009
        list_add(&tt_req_node->list, &bat_priv->tt_req_list);
 
1010
unlock:
 
1011
        spin_unlock_bh(&bat_priv->tt_req_list_lock);
 
1012
        return tt_req_node;
 
1013
}
 
1014
 
 
1015
/* data_ptr is useless here, but has to be kept to respect the prototype */
 
1016
static int tt_local_valid_entry(const void *entry_ptr, const void *data_ptr)
 
1017
{
 
1018
        const struct tt_local_entry *tt_local_entry = entry_ptr;
 
1019
 
 
1020
        if (tt_local_entry->flags & TT_CLIENT_NEW)
 
1021
                return 0;
 
1022
        return 1;
 
1023
}
 
1024
 
 
1025
static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr)
 
1026
{
 
1027
        const struct tt_global_entry *tt_global_entry = entry_ptr;
 
1028
        const struct orig_node *orig_node = data_ptr;
 
1029
 
 
1030
        if (tt_global_entry->flags & TT_CLIENT_ROAM)
 
1031
                return 0;
 
1032
 
 
1033
        return (tt_global_entry->orig_node == orig_node);
 
1034
}
 
1035
 
 
1036
static struct sk_buff *tt_response_fill_table(uint16_t tt_len, uint8_t ttvn,
 
1037
                                              struct hashtable_t *hash,
 
1038
                                              struct hard_iface *primary_if,
 
1039
                                              int (*valid_cb)(const void *,
 
1040
                                                              const void *),
 
1041
                                              void *cb_data)
 
1042
{
 
1043
        struct tt_local_entry *tt_local_entry;
 
1044
        struct tt_query_packet *tt_response;
 
1045
        struct tt_change *tt_change;
 
1046
        struct hlist_node *node;
 
1047
        struct hlist_head *head;
 
1048
        struct sk_buff *skb = NULL;
 
1049
        uint16_t tt_tot, tt_count;
 
1050
        ssize_t tt_query_size = sizeof(struct tt_query_packet);
 
1051
        int i;
 
1052
 
 
1053
        if (tt_query_size + tt_len > primary_if->soft_iface->mtu) {
 
1054
                tt_len = primary_if->soft_iface->mtu - tt_query_size;
 
1055
                tt_len -= tt_len % sizeof(struct tt_change);
 
1056
        }
 
1057
        tt_tot = tt_len / sizeof(struct tt_change);
 
1058
 
 
1059
        skb = dev_alloc_skb(tt_query_size + tt_len + ETH_HLEN);
 
1060
        if (!skb)
 
1061
                goto out;
 
1062
 
 
1063
        skb_reserve(skb, ETH_HLEN);
 
1064
        tt_response = (struct tt_query_packet *)skb_put(skb,
 
1065
                                                     tt_query_size + tt_len);
 
1066
        tt_response->ttvn = ttvn;
 
1067
 
 
1068
        tt_change = (struct tt_change *)(skb->data + tt_query_size);
 
1069
        tt_count = 0;
 
1070
 
 
1071
        rcu_read_lock();
 
1072
        for (i = 0; i < hash->size; i++) {
 
1073
                head = &hash->table[i];
 
1074
 
 
1075
                hlist_for_each_entry_rcu(tt_local_entry, node,
 
1076
                                         head, hash_entry) {
 
1077
                        if (tt_count == tt_tot)
 
1078
                                break;
 
1079
 
 
1080
                        if ((valid_cb) && (!valid_cb(tt_local_entry, cb_data)))
 
1081
                                continue;
 
1082
 
 
1083
                        memcpy(tt_change->addr, tt_local_entry->addr, ETH_ALEN);
 
1084
                        tt_change->flags = NO_FLAGS;
 
1085
 
 
1086
                        tt_count++;
 
1087
                        tt_change++;
 
1088
                }
 
1089
        }
 
1090
        rcu_read_unlock();
 
1091
 
 
1092
        /* store in the message the number of entries we have successfully
 
1093
         * copied */
 
1094
        tt_response->tt_data = htons(tt_count);
 
1095
 
 
1096
out:
 
1097
        return skb;
 
1098
}
 
1099
 
 
1100
static int send_tt_request(struct bat_priv *bat_priv,
 
1101
                           struct orig_node *dst_orig_node,
 
1102
                           uint8_t ttvn, uint16_t tt_crc, bool full_table)
 
1103
{
 
1104
        struct sk_buff *skb = NULL;
 
1105
        struct tt_query_packet *tt_request;
 
1106
        struct neigh_node *neigh_node = NULL;
 
1107
        struct hard_iface *primary_if;
 
1108
        struct tt_req_node *tt_req_node = NULL;
 
1109
        int ret = 1;
 
1110
 
 
1111
        primary_if = primary_if_get_selected(bat_priv);
 
1112
        if (!primary_if)
 
1113
                goto out;
 
1114
 
 
1115
        /* The new tt_req will be issued only if I'm not waiting for a
 
1116
         * reply from the same orig_node yet */
 
1117
        tt_req_node = new_tt_req_node(bat_priv, dst_orig_node);
 
1118
        if (!tt_req_node)
 
1119
                goto out;
 
1120
 
 
1121
        skb = dev_alloc_skb(sizeof(struct tt_query_packet) + ETH_HLEN);
 
1122
        if (!skb)
 
1123
                goto out;
 
1124
 
 
1125
        skb_reserve(skb, ETH_HLEN);
 
1126
 
 
1127
        tt_request = (struct tt_query_packet *)skb_put(skb,
 
1128
                                sizeof(struct tt_query_packet));
 
1129
 
 
1130
        tt_request->packet_type = BAT_TT_QUERY;
 
1131
        tt_request->version = COMPAT_VERSION;
 
1132
        memcpy(tt_request->src, primary_if->net_dev->dev_addr, ETH_ALEN);
 
1133
        memcpy(tt_request->dst, dst_orig_node->orig, ETH_ALEN);
 
1134
        tt_request->ttl = TTL;
 
1135
        tt_request->ttvn = ttvn;
 
1136
        tt_request->tt_data = tt_crc;
 
1137
        tt_request->flags = TT_REQUEST;
 
1138
 
 
1139
        if (full_table)
 
1140
                tt_request->flags |= TT_FULL_TABLE;
 
1141
 
 
1142
        neigh_node = orig_node_get_router(dst_orig_node);
 
1143
        if (!neigh_node)
 
1144
                goto out;
 
1145
 
 
1146
        bat_dbg(DBG_TT, bat_priv, "Sending TT_REQUEST to %pM via %pM "
 
1147
                "[%c]\n", dst_orig_node->orig, neigh_node->addr,
 
1148
                (full_table ? 'F' : '.'));
 
1149
 
 
1150
        send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
 
1151
        ret = 0;
 
1152
 
 
1153
out:
 
1154
        if (neigh_node)
 
1155
                neigh_node_free_ref(neigh_node);
 
1156
        if (primary_if)
 
1157
                hardif_free_ref(primary_if);
 
1158
        if (ret)
 
1159
                kfree_skb(skb);
 
1160
        if (ret && tt_req_node) {
 
1161
                spin_lock_bh(&bat_priv->tt_req_list_lock);
 
1162
                list_del(&tt_req_node->list);
 
1163
                spin_unlock_bh(&bat_priv->tt_req_list_lock);
 
1164
                kfree(tt_req_node);
 
1165
        }
 
1166
        return ret;
 
1167
}
 
1168
 
 
1169
static bool send_other_tt_response(struct bat_priv *bat_priv,
 
1170
                                   struct tt_query_packet *tt_request)
 
1171
{
 
1172
        struct orig_node *req_dst_orig_node = NULL, *res_dst_orig_node = NULL;
 
1173
        struct neigh_node *neigh_node = NULL;
 
1174
        struct hard_iface *primary_if = NULL;
 
1175
        uint8_t orig_ttvn, req_ttvn, ttvn;
 
1176
        int ret = false;
 
1177
        unsigned char *tt_buff;
 
1178
        bool full_table;
 
1179
        uint16_t tt_len, tt_tot;
 
1180
        struct sk_buff *skb = NULL;
 
1181
        struct tt_query_packet *tt_response;
 
1182
 
 
1183
        bat_dbg(DBG_TT, bat_priv,
 
1184
                "Received TT_REQUEST from %pM for "
 
1185
                "ttvn: %u (%pM) [%c]\n", tt_request->src,
 
1186
                tt_request->ttvn, tt_request->dst,
 
1187
                (tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
 
1188
 
 
1189
        /* Let's get the orig node of the REAL destination */
 
1190
        req_dst_orig_node = get_orig_node(bat_priv, tt_request->dst);
 
1191
        if (!req_dst_orig_node)
 
1192
                goto out;
 
1193
 
 
1194
        res_dst_orig_node = get_orig_node(bat_priv, tt_request->src);
 
1195
        if (!res_dst_orig_node)
 
1196
                goto out;
 
1197
 
 
1198
        neigh_node = orig_node_get_router(res_dst_orig_node);
 
1199
        if (!neigh_node)
 
1200
                goto out;
 
1201
 
 
1202
        primary_if = primary_if_get_selected(bat_priv);
 
1203
        if (!primary_if)
 
1204
                goto out;
 
1205
 
 
1206
        orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
 
1207
        req_ttvn = tt_request->ttvn;
 
1208
 
 
1209
        /* I don't have the requested data */
 
1210
        if (orig_ttvn != req_ttvn ||
 
1211
            tt_request->tt_data != req_dst_orig_node->tt_crc)
 
1212
                goto out;
 
1213
 
 
1214
        /* If the full table has been explicitly requested */
 
1215
        if (tt_request->flags & TT_FULL_TABLE ||
 
1216
            !req_dst_orig_node->tt_buff)
 
1217
                full_table = true;
 
1218
        else
 
1219
                full_table = false;
 
1220
 
 
1221
        /* In this version, fragmentation is not implemented, then
 
1222
         * I'll send only one packet with as much TT entries as I can */
 
1223
        if (!full_table) {
 
1224
                spin_lock_bh(&req_dst_orig_node->tt_buff_lock);
 
1225
                tt_len = req_dst_orig_node->tt_buff_len;
 
1226
                tt_tot = tt_len / sizeof(struct tt_change);
 
1227
 
 
1228
                skb = dev_alloc_skb(sizeof(struct tt_query_packet) +
 
1229
                                    tt_len + ETH_HLEN);
 
1230
                if (!skb)
 
1231
                        goto unlock;
 
1232
 
 
1233
                skb_reserve(skb, ETH_HLEN);
 
1234
                tt_response = (struct tt_query_packet *)skb_put(skb,
 
1235
                                sizeof(struct tt_query_packet) + tt_len);
 
1236
                tt_response->ttvn = req_ttvn;
 
1237
                tt_response->tt_data = htons(tt_tot);
 
1238
 
 
1239
                tt_buff = skb->data + sizeof(struct tt_query_packet);
 
1240
                /* Copy the last orig_node's OGM buffer */
 
1241
                memcpy(tt_buff, req_dst_orig_node->tt_buff,
 
1242
                       req_dst_orig_node->tt_buff_len);
 
1243
 
 
1244
                spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
 
1245
        } else {
 
1246
                tt_len = (uint16_t)atomic_read(&req_dst_orig_node->tt_size) *
 
1247
                                                sizeof(struct tt_change);
 
1248
                ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
 
1249
 
 
1250
                skb = tt_response_fill_table(tt_len, ttvn,
 
1251
                                             bat_priv->tt_global_hash,
 
1252
                                             primary_if, tt_global_valid_entry,
 
1253
                                             req_dst_orig_node);
 
1254
                if (!skb)
 
1255
                        goto out;
 
1256
 
 
1257
                tt_response = (struct tt_query_packet *)skb->data;
 
1258
        }
 
1259
 
 
1260
        tt_response->packet_type = BAT_TT_QUERY;
 
1261
        tt_response->version = COMPAT_VERSION;
 
1262
        tt_response->ttl = TTL;
 
1263
        memcpy(tt_response->src, req_dst_orig_node->orig, ETH_ALEN);
 
1264
        memcpy(tt_response->dst, tt_request->src, ETH_ALEN);
 
1265
        tt_response->flags = TT_RESPONSE;
 
1266
 
 
1267
        if (full_table)
 
1268
                tt_response->flags |= TT_FULL_TABLE;
 
1269
 
 
1270
        bat_dbg(DBG_TT, bat_priv,
 
1271
                "Sending TT_RESPONSE %pM via %pM for %pM (ttvn: %u)\n",
 
1272
                res_dst_orig_node->orig, neigh_node->addr,
 
1273
                req_dst_orig_node->orig, req_ttvn);
 
1274
 
 
1275
        send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
 
1276
        ret = true;
 
1277
        goto out;
 
1278
 
 
1279
unlock:
 
1280
        spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
 
1281
 
 
1282
out:
 
1283
        if (res_dst_orig_node)
 
1284
                orig_node_free_ref(res_dst_orig_node);
 
1285
        if (req_dst_orig_node)
 
1286
                orig_node_free_ref(req_dst_orig_node);
 
1287
        if (neigh_node)
 
1288
                neigh_node_free_ref(neigh_node);
 
1289
        if (primary_if)
 
1290
                hardif_free_ref(primary_if);
 
1291
        if (!ret)
 
1292
                kfree_skb(skb);
 
1293
        return ret;
 
1294
 
 
1295
}
 
1296
static bool send_my_tt_response(struct bat_priv *bat_priv,
 
1297
                                struct tt_query_packet *tt_request)
 
1298
{
 
1299
        struct orig_node *orig_node = NULL;
 
1300
        struct neigh_node *neigh_node = NULL;
 
1301
        struct hard_iface *primary_if = NULL;
 
1302
        uint8_t my_ttvn, req_ttvn, ttvn;
 
1303
        int ret = false;
 
1304
        unsigned char *tt_buff;
 
1305
        bool full_table;
 
1306
        uint16_t tt_len, tt_tot;
 
1307
        struct sk_buff *skb = NULL;
 
1308
        struct tt_query_packet *tt_response;
 
1309
 
 
1310
        bat_dbg(DBG_TT, bat_priv,
 
1311
                "Received TT_REQUEST from %pM for "
 
1312
                "ttvn: %u (me) [%c]\n", tt_request->src,
 
1313
                tt_request->ttvn,
 
1314
                (tt_request->flags & TT_FULL_TABLE ? 'F' : '.'));
 
1315
 
 
1316
 
 
1317
        my_ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
 
1318
        req_ttvn = tt_request->ttvn;
 
1319
 
 
1320
        orig_node = get_orig_node(bat_priv, tt_request->src);
 
1321
        if (!orig_node)
 
1322
                goto out;
 
1323
 
 
1324
        neigh_node = orig_node_get_router(orig_node);
 
1325
        if (!neigh_node)
 
1326
                goto out;
 
1327
 
 
1328
        primary_if = primary_if_get_selected(bat_priv);
 
1329
        if (!primary_if)
 
1330
                goto out;
 
1331
 
 
1332
        /* If the full table has been explicitly requested or the gap
 
1333
         * is too big send the whole local translation table */
 
1334
        if (tt_request->flags & TT_FULL_TABLE || my_ttvn != req_ttvn ||
 
1335
            !bat_priv->tt_buff)
 
1336
                full_table = true;
 
1337
        else
 
1338
                full_table = false;
 
1339
 
 
1340
        /* In this version, fragmentation is not implemented, then
 
1341
         * I'll send only one packet with as much TT entries as I can */
 
1342
        if (!full_table) {
 
1343
                spin_lock_bh(&bat_priv->tt_buff_lock);
 
1344
                tt_len = bat_priv->tt_buff_len;
 
1345
                tt_tot = tt_len / sizeof(struct tt_change);
 
1346
 
 
1347
                skb = dev_alloc_skb(sizeof(struct tt_query_packet) +
 
1348
                                    tt_len + ETH_HLEN);
 
1349
                if (!skb)
 
1350
                        goto unlock;
 
1351
 
 
1352
                skb_reserve(skb, ETH_HLEN);
 
1353
                tt_response = (struct tt_query_packet *)skb_put(skb,
 
1354
                                sizeof(struct tt_query_packet) + tt_len);
 
1355
                tt_response->ttvn = req_ttvn;
 
1356
                tt_response->tt_data = htons(tt_tot);
 
1357
 
 
1358
                tt_buff = skb->data + sizeof(struct tt_query_packet);
 
1359
                memcpy(tt_buff, bat_priv->tt_buff,
 
1360
                       bat_priv->tt_buff_len);
 
1361
                spin_unlock_bh(&bat_priv->tt_buff_lock);
 
1362
        } else {
 
1363
                tt_len = (uint16_t)atomic_read(&bat_priv->num_local_tt) *
 
1364
                                                sizeof(struct tt_change);
 
1365
                ttvn = (uint8_t)atomic_read(&bat_priv->ttvn);
 
1366
 
 
1367
                skb = tt_response_fill_table(tt_len, ttvn,
 
1368
                                             bat_priv->tt_local_hash,
 
1369
                                             primary_if, tt_local_valid_entry,
 
1370
                                             NULL);
 
1371
                if (!skb)
 
1372
                        goto out;
 
1373
 
 
1374
                tt_response = (struct tt_query_packet *)skb->data;
 
1375
        }
 
1376
 
 
1377
        tt_response->packet_type = BAT_TT_QUERY;
 
1378
        tt_response->version = COMPAT_VERSION;
 
1379
        tt_response->ttl = TTL;
 
1380
        memcpy(tt_response->src, primary_if->net_dev->dev_addr, ETH_ALEN);
 
1381
        memcpy(tt_response->dst, tt_request->src, ETH_ALEN);
 
1382
        tt_response->flags = TT_RESPONSE;
 
1383
 
 
1384
        if (full_table)
 
1385
                tt_response->flags |= TT_FULL_TABLE;
 
1386
 
 
1387
        bat_dbg(DBG_TT, bat_priv,
 
1388
                "Sending TT_RESPONSE to %pM via %pM [%c]\n",
 
1389
                orig_node->orig, neigh_node->addr,
 
1390
                (tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
 
1391
 
 
1392
        send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
 
1393
        ret = true;
 
1394
        goto out;
 
1395
 
 
1396
unlock:
 
1397
        spin_unlock_bh(&bat_priv->tt_buff_lock);
 
1398
out:
 
1399
        if (orig_node)
 
1400
                orig_node_free_ref(orig_node);
 
1401
        if (neigh_node)
 
1402
                neigh_node_free_ref(neigh_node);
 
1403
        if (primary_if)
 
1404
                hardif_free_ref(primary_if);
 
1405
        if (!ret)
 
1406
                kfree_skb(skb);
 
1407
        /* This packet was for me, so it doesn't need to be re-routed */
 
1408
        return true;
 
1409
}
 
1410
 
 
1411
bool send_tt_response(struct bat_priv *bat_priv,
 
1412
                      struct tt_query_packet *tt_request)
 
1413
{
 
1414
        if (is_my_mac(tt_request->dst))
 
1415
                return send_my_tt_response(bat_priv, tt_request);
 
1416
        else
 
1417
                return send_other_tt_response(bat_priv, tt_request);
 
1418
}
 
1419
 
 
1420
static void _tt_update_changes(struct bat_priv *bat_priv,
 
1421
                               struct orig_node *orig_node,
 
1422
                               struct tt_change *tt_change,
 
1423
                               uint16_t tt_num_changes, uint8_t ttvn)
 
1424
{
 
1425
        int i;
 
1426
 
 
1427
        for (i = 0; i < tt_num_changes; i++) {
 
1428
                if ((tt_change + i)->flags & TT_CLIENT_DEL)
 
1429
                        tt_global_del(bat_priv, orig_node,
 
1430
                                      (tt_change + i)->addr,
 
1431
                                      "tt removed by changes",
 
1432
                                      (tt_change + i)->flags & TT_CLIENT_ROAM);
 
1433
                else
 
1434
                        if (!tt_global_add(bat_priv, orig_node,
 
1435
                                           (tt_change + i)->addr, ttvn, false,
 
1436
                                           (tt_change + i)->flags &
 
1437
                                                        TT_CLIENT_WIFI))
 
1438
                                /* In case of problem while storing a
 
1439
                                 * global_entry, we stop the updating
 
1440
                                 * procedure without committing the
 
1441
                                 * ttvn change. This will avoid to send
 
1442
                                 * corrupted data on tt_request
 
1443
                                 */
 
1444
                                return;
 
1445
        }
 
1446
}
 
1447
 
 
1448
static void tt_fill_gtable(struct bat_priv *bat_priv,
 
1449
                           struct tt_query_packet *tt_response)
 
1450
{
 
1451
        struct orig_node *orig_node = NULL;
 
1452
 
 
1453
        orig_node = orig_hash_find(bat_priv, tt_response->src);
 
1454
        if (!orig_node)
 
1455
                goto out;
 
1456
 
 
1457
        /* Purge the old table first.. */
 
1458
        tt_global_del_orig(bat_priv, orig_node, "Received full table");
 
1459
 
 
1460
        _tt_update_changes(bat_priv, orig_node,
 
1461
                           (struct tt_change *)(tt_response + 1),
 
1462
                           tt_response->tt_data, tt_response->ttvn);
 
1463
 
 
1464
        spin_lock_bh(&orig_node->tt_buff_lock);
 
1465
        kfree(orig_node->tt_buff);
 
1466
        orig_node->tt_buff_len = 0;
 
1467
        orig_node->tt_buff = NULL;
 
1468
        spin_unlock_bh(&orig_node->tt_buff_lock);
 
1469
 
 
1470
        atomic_set(&orig_node->last_ttvn, tt_response->ttvn);
 
1471
 
 
1472
out:
 
1473
        if (orig_node)
 
1474
                orig_node_free_ref(orig_node);
 
1475
}
 
1476
 
 
1477
static void tt_update_changes(struct bat_priv *bat_priv,
 
1478
                              struct orig_node *orig_node,
 
1479
                              uint16_t tt_num_changes, uint8_t ttvn,
 
1480
                              struct tt_change *tt_change)
 
1481
{
 
1482
        _tt_update_changes(bat_priv, orig_node, tt_change, tt_num_changes,
 
1483
                           ttvn);
 
1484
 
 
1485
        tt_save_orig_buffer(bat_priv, orig_node, (unsigned char *)tt_change,
 
1486
                            tt_num_changes);
 
1487
        atomic_set(&orig_node->last_ttvn, ttvn);
 
1488
}
 
1489
 
 
1490
bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr)
 
1491
{
 
1492
        struct tt_local_entry *tt_local_entry = NULL;
 
1493
        bool ret = false;
 
1494
 
 
1495
        tt_local_entry = tt_local_hash_find(bat_priv, addr);
 
1496
        if (!tt_local_entry)
 
1497
                goto out;
 
1498
        /* Check if the client has been logically deleted (but is kept for
 
1499
         * consistency purpose) */
 
1500
        if (tt_local_entry->flags & TT_CLIENT_PENDING)
 
1501
                goto out;
 
1502
        ret = true;
 
1503
out:
 
1504
        if (tt_local_entry)
 
1505
                tt_local_entry_free_ref(tt_local_entry);
 
1506
        return ret;
 
1507
}
 
1508
 
 
1509
void handle_tt_response(struct bat_priv *bat_priv,
 
1510
                        struct tt_query_packet *tt_response)
 
1511
{
 
1512
        struct tt_req_node *node, *safe;
 
1513
        struct orig_node *orig_node = NULL;
 
1514
 
 
1515
        bat_dbg(DBG_TT, bat_priv, "Received TT_RESPONSE from %pM for "
 
1516
                "ttvn %d t_size: %d [%c]\n",
 
1517
                tt_response->src, tt_response->ttvn,
 
1518
                tt_response->tt_data,
 
1519
                (tt_response->flags & TT_FULL_TABLE ? 'F' : '.'));
 
1520
 
 
1521
        orig_node = orig_hash_find(bat_priv, tt_response->src);
 
1522
        if (!orig_node)
 
1523
                goto out;
 
1524
 
 
1525
        if (tt_response->flags & TT_FULL_TABLE)
 
1526
                tt_fill_gtable(bat_priv, tt_response);
 
1527
        else
 
1528
                tt_update_changes(bat_priv, orig_node, tt_response->tt_data,
 
1529
                                  tt_response->ttvn,
 
1530
                                  (struct tt_change *)(tt_response + 1));
 
1531
 
 
1532
        /* Delete the tt_req_node from pending tt_requests list */
 
1533
        spin_lock_bh(&bat_priv->tt_req_list_lock);
 
1534
        list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
 
1535
                if (!compare_eth(node->addr, tt_response->src))
 
1536
                        continue;
 
1537
                list_del(&node->list);
 
1538
                kfree(node);
 
1539
        }
 
1540
        spin_unlock_bh(&bat_priv->tt_req_list_lock);
 
1541
 
 
1542
        /* Recalculate the CRC for this orig_node and store it */
 
1543
        orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
 
1544
        /* Roaming phase is over: tables are in sync again. I can
 
1545
         * unset the flag */
 
1546
        orig_node->tt_poss_change = false;
 
1547
out:
 
1548
        if (orig_node)
 
1549
                orig_node_free_ref(orig_node);
 
1550
}
 
1551
 
 
1552
int tt_init(struct bat_priv *bat_priv)
 
1553
{
 
1554
        if (!tt_local_init(bat_priv))
 
1555
                return 0;
 
1556
 
 
1557
        if (!tt_global_init(bat_priv))
 
1558
                return 0;
 
1559
 
 
1560
        tt_start_timer(bat_priv);
 
1561
 
 
1562
        return 1;
 
1563
}
 
1564
 
 
1565
static void tt_roam_list_free(struct bat_priv *bat_priv)
 
1566
{
 
1567
        struct tt_roam_node *node, *safe;
 
1568
 
 
1569
        spin_lock_bh(&bat_priv->tt_roam_list_lock);
 
1570
 
 
1571
        list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) {
 
1572
                list_del(&node->list);
 
1573
                kfree(node);
 
1574
        }
 
1575
 
 
1576
        spin_unlock_bh(&bat_priv->tt_roam_list_lock);
 
1577
}
 
1578
 
 
1579
static void tt_roam_purge(struct bat_priv *bat_priv)
 
1580
{
 
1581
        struct tt_roam_node *node, *safe;
 
1582
 
 
1583
        spin_lock_bh(&bat_priv->tt_roam_list_lock);
 
1584
        list_for_each_entry_safe(node, safe, &bat_priv->tt_roam_list, list) {
 
1585
                if (!is_out_of_time(node->first_time,
 
1586
                                    ROAMING_MAX_TIME * 1000))
 
1587
                        continue;
 
1588
 
 
1589
                list_del(&node->list);
 
1590
                kfree(node);
 
1591
        }
 
1592
        spin_unlock_bh(&bat_priv->tt_roam_list_lock);
 
1593
}
 
1594
 
 
1595
/* This function checks whether the client already reached the
 
1596
 * maximum number of possible roaming phases. In this case the ROAMING_ADV
 
1597
 * will not be sent.
 
1598
 *
 
1599
 * returns true if the ROAMING_ADV can be sent, false otherwise */
 
1600
static bool tt_check_roam_count(struct bat_priv *bat_priv,
 
1601
                                uint8_t *client)
 
1602
{
 
1603
        struct tt_roam_node *tt_roam_node;
 
1604
        bool ret = false;
 
1605
 
 
1606
        spin_lock_bh(&bat_priv->tt_roam_list_lock);
 
1607
        /* The new tt_req will be issued only if I'm not waiting for a
 
1608
         * reply from the same orig_node yet */
 
1609
        list_for_each_entry(tt_roam_node, &bat_priv->tt_roam_list, list) {
 
1610
                if (!compare_eth(tt_roam_node->addr, client))
 
1611
                        continue;
 
1612
 
 
1613
                if (is_out_of_time(tt_roam_node->first_time,
 
1614
                                   ROAMING_MAX_TIME * 1000))
 
1615
                        continue;
 
1616
 
 
1617
                if (!atomic_dec_not_zero(&tt_roam_node->counter))
 
1618
                        /* Sorry, you roamed too many times! */
 
1619
                        goto unlock;
 
1620
                ret = true;
 
1621
                break;
 
1622
        }
 
1623
 
 
1624
        if (!ret) {
 
1625
                tt_roam_node = kmalloc(sizeof(*tt_roam_node), GFP_ATOMIC);
 
1626
                if (!tt_roam_node)
 
1627
                        goto unlock;
 
1628
 
 
1629
                tt_roam_node->first_time = jiffies;
 
1630
                atomic_set(&tt_roam_node->counter, ROAMING_MAX_COUNT - 1);
 
1631
                memcpy(tt_roam_node->addr, client, ETH_ALEN);
 
1632
 
 
1633
                list_add(&tt_roam_node->list, &bat_priv->tt_roam_list);
 
1634
                ret = true;
 
1635
        }
 
1636
 
 
1637
unlock:
 
1638
        spin_unlock_bh(&bat_priv->tt_roam_list_lock);
 
1639
        return ret;
 
1640
}
 
1641
 
 
1642
void send_roam_adv(struct bat_priv *bat_priv, uint8_t *client,
 
1643
                   struct orig_node *orig_node)
 
1644
{
 
1645
        struct neigh_node *neigh_node = NULL;
 
1646
        struct sk_buff *skb = NULL;
 
1647
        struct roam_adv_packet *roam_adv_packet;
 
1648
        int ret = 1;
 
1649
        struct hard_iface *primary_if;
 
1650
 
 
1651
        /* before going on we have to check whether the client has
 
1652
         * already roamed to us too many times */
 
1653
        if (!tt_check_roam_count(bat_priv, client))
 
1654
                goto out;
 
1655
 
 
1656
        skb = dev_alloc_skb(sizeof(struct roam_adv_packet) + ETH_HLEN);
 
1657
        if (!skb)
 
1658
                goto out;
 
1659
 
 
1660
        skb_reserve(skb, ETH_HLEN);
 
1661
 
 
1662
        roam_adv_packet = (struct roam_adv_packet *)skb_put(skb,
 
1663
                                        sizeof(struct roam_adv_packet));
 
1664
 
 
1665
        roam_adv_packet->packet_type = BAT_ROAM_ADV;
 
1666
        roam_adv_packet->version = COMPAT_VERSION;
 
1667
        roam_adv_packet->ttl = TTL;
 
1668
        primary_if = primary_if_get_selected(bat_priv);
 
1669
        if (!primary_if)
 
1670
                goto out;
 
1671
        memcpy(roam_adv_packet->src, primary_if->net_dev->dev_addr, ETH_ALEN);
 
1672
        hardif_free_ref(primary_if);
 
1673
        memcpy(roam_adv_packet->dst, orig_node->orig, ETH_ALEN);
 
1674
        memcpy(roam_adv_packet->client, client, ETH_ALEN);
 
1675
 
 
1676
        neigh_node = orig_node_get_router(orig_node);
 
1677
        if (!neigh_node)
 
1678
                goto out;
 
1679
 
 
1680
        bat_dbg(DBG_TT, bat_priv,
 
1681
                "Sending ROAMING_ADV to %pM (client %pM) via %pM\n",
 
1682
                orig_node->orig, client, neigh_node->addr);
 
1683
 
 
1684
        send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
 
1685
        ret = 0;
 
1686
 
 
1687
out:
 
1688
        if (neigh_node)
 
1689
                neigh_node_free_ref(neigh_node);
 
1690
        if (ret)
 
1691
                kfree_skb(skb);
 
1692
        return;
 
1693
}
 
1694
 
 
1695
static void tt_purge(struct work_struct *work)
 
1696
{
 
1697
        struct delayed_work *delayed_work =
 
1698
                container_of(work, struct delayed_work, work);
 
1699
        struct bat_priv *bat_priv =
 
1700
                container_of(delayed_work, struct bat_priv, tt_work);
 
1701
 
 
1702
        tt_local_purge(bat_priv);
 
1703
        tt_global_roam_purge(bat_priv);
 
1704
        tt_req_purge(bat_priv);
 
1705
        tt_roam_purge(bat_priv);
 
1706
 
 
1707
        tt_start_timer(bat_priv);
 
1708
}
 
1709
 
 
1710
void tt_free(struct bat_priv *bat_priv)
 
1711
{
 
1712
        cancel_delayed_work_sync(&bat_priv->tt_work);
 
1713
 
 
1714
        tt_local_table_free(bat_priv);
 
1715
        tt_global_table_free(bat_priv);
 
1716
        tt_req_list_free(bat_priv);
 
1717
        tt_changes_list_free(bat_priv);
 
1718
        tt_roam_list_free(bat_priv);
 
1719
 
 
1720
        kfree(bat_priv->tt_buff);
 
1721
}
 
1722
 
 
1723
/* This function will reset the specified flags from all the entries in
 
1724
 * the given hash table and will increment num_local_tt for each involved
 
1725
 * entry */
 
1726
static void tt_local_reset_flags(struct bat_priv *bat_priv, uint16_t flags)
 
1727
{
 
1728
        int i;
 
1729
        struct hashtable_t *hash = bat_priv->tt_local_hash;
 
1730
        struct hlist_head *head;
 
1731
        struct hlist_node *node;
 
1732
        struct tt_local_entry *tt_local_entry;
 
1733
 
 
1734
        if (!hash)
 
1735
                return;
 
1736
 
 
1737
        for (i = 0; i < hash->size; i++) {
 
1738
                head = &hash->table[i];
 
1739
 
 
1740
                rcu_read_lock();
 
1741
                hlist_for_each_entry_rcu(tt_local_entry, node,
 
1742
                                         head, hash_entry) {
 
1743
                        if (!(tt_local_entry->flags & flags))
 
1744
                                continue;
 
1745
                        tt_local_entry->flags &= ~flags;
 
1746
                        atomic_inc(&bat_priv->num_local_tt);
 
1747
                }
 
1748
                rcu_read_unlock();
 
1749
        }
 
1750
 
 
1751
}
 
1752
 
 
1753
/* Purge out all the tt local entries marked with TT_CLIENT_PENDING */
 
1754
static void tt_local_purge_pending_clients(struct bat_priv *bat_priv)
 
1755
{
 
1756
        struct hashtable_t *hash = bat_priv->tt_local_hash;
 
1757
        struct tt_local_entry *tt_local_entry;
 
1758
        struct hlist_node *node, *node_tmp;
 
1759
        struct hlist_head *head;
 
1760
        spinlock_t *list_lock; /* protects write access to the hash lists */
 
1761
        int i;
 
1762
 
 
1763
        if (!hash)
 
1764
                return;
 
1765
 
 
1766
        for (i = 0; i < hash->size; i++) {
 
1767
                head = &hash->table[i];
 
1768
                list_lock = &hash->list_locks[i];
 
1769
 
 
1770
                spin_lock_bh(list_lock);
 
1771
                hlist_for_each_entry_safe(tt_local_entry, node, node_tmp,
 
1772
                                          head, hash_entry) {
 
1773
                        if (!(tt_local_entry->flags & TT_CLIENT_PENDING))
 
1774
                                continue;
 
1775
 
 
1776
                        bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry "
 
1777
                                "(%pM): pending\n", tt_local_entry->addr);
 
1778
 
 
1779
                        atomic_dec(&bat_priv->num_local_tt);
 
1780
                        hlist_del_rcu(node);
 
1781
                        tt_local_entry_free_ref(tt_local_entry);
 
1782
                }
 
1783
                spin_unlock_bh(list_lock);
 
1784
        }
 
1785
 
 
1786
}
 
1787
 
 
1788
void tt_commit_changes(struct bat_priv *bat_priv)
 
1789
{
 
1790
        tt_local_reset_flags(bat_priv, TT_CLIENT_NEW);
 
1791
        tt_local_purge_pending_clients(bat_priv);
 
1792
 
 
1793
        /* Increment the TTVN only once per OGM interval */
 
1794
        atomic_inc(&bat_priv->ttvn);
 
1795
        bat_priv->tt_poss_change = false;
 
1796
}
 
1797
 
 
1798
bool is_ap_isolated(struct bat_priv *bat_priv, uint8_t *src, uint8_t *dst)
 
1799
{
 
1800
        struct tt_local_entry *tt_local_entry = NULL;
 
1801
        struct tt_global_entry *tt_global_entry = NULL;
 
1802
        bool ret = true;
 
1803
 
 
1804
        if (!atomic_read(&bat_priv->ap_isolation))
 
1805
                return false;
 
1806
 
 
1807
        tt_local_entry = tt_local_hash_find(bat_priv, dst);
 
1808
        if (!tt_local_entry)
 
1809
                goto out;
 
1810
 
 
1811
        tt_global_entry = tt_global_hash_find(bat_priv, src);
 
1812
        if (!tt_global_entry)
 
1813
                goto out;
 
1814
 
 
1815
        if (_is_ap_isolated(tt_local_entry, tt_global_entry))
 
1816
                goto out;
 
1817
 
 
1818
        ret = false;
 
1819
 
 
1820
out:
 
1821
        if (tt_global_entry)
 
1822
                tt_global_entry_free_ref(tt_global_entry);
 
1823
        if (tt_local_entry)
 
1824
                tt_local_entry_free_ref(tt_local_entry);
 
1825
        return ret;
 
1826
}
 
1827
 
 
1828
void tt_update_orig(struct bat_priv *bat_priv, struct orig_node *orig_node,
 
1829
                    const unsigned char *tt_buff, uint8_t tt_num_changes,
 
1830
                    uint8_t ttvn, uint16_t tt_crc)
 
1831
{
 
1832
        uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
 
1833
        bool full_table = true;
 
1834
 
 
1835
        /* the ttvn increased by one -> we can apply the attached changes */
 
1836
        if (ttvn - orig_ttvn == 1) {
 
1837
                /* the OGM could not contain the changes due to their size or
 
1838
                 * because they have already been sent TT_OGM_APPEND_MAX times.
 
1839
                 * In this case send a tt request */
 
1840
                if (!tt_num_changes) {
 
1841
                        full_table = false;
 
1842
                        goto request_table;
 
1843
                }
 
1844
 
 
1845
                tt_update_changes(bat_priv, orig_node, tt_num_changes, ttvn,
 
1846
                                  (struct tt_change *)tt_buff);
 
1847
 
 
1848
                /* Even if we received the precomputed crc with the OGM, we
 
1849
                 * prefer to recompute it to spot any possible inconsistency
 
1850
                 * in the global table */
 
1851
                orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);
 
1852
 
 
1853
                /* The ttvn alone is not enough to guarantee consistency
 
1854
                 * because a single value could represent different states
 
1855
                 * (due to the wrap around). Thus a node has to check whether
 
1856
                 * the resulting table (after applying the changes) is still
 
1857
                 * consistent or not. E.g. a node could disconnect while its
 
1858
                 * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case
 
1859
                 * checking the CRC value is mandatory to detect the
 
1860
                 * inconsistency */
 
1861
                if (orig_node->tt_crc != tt_crc)
 
1862
                        goto request_table;
 
1863
 
 
1864
                /* Roaming phase is over: tables are in sync again. I can
 
1865
                 * unset the flag */
 
1866
                orig_node->tt_poss_change = false;
 
1867
        } else {
 
1868
                /* if we missed more than one change or our tables are not
 
1869
                 * in sync anymore -> request fresh tt data */
 
1870
                if (ttvn != orig_ttvn || orig_node->tt_crc != tt_crc) {
 
1871
request_table:
 
1872
                        bat_dbg(DBG_TT, bat_priv, "TT inconsistency for %pM. "
 
1873
                                "Need to retrieve the correct information "
 
1874
                                "(ttvn: %u last_ttvn: %u crc: %u last_crc: "
 
1875
                                "%u num_changes: %u)\n", orig_node->orig, ttvn,
 
1876
                                orig_ttvn, tt_crc, orig_node->tt_crc,
 
1877
                                tt_num_changes);
 
1878
                        send_tt_request(bat_priv, orig_node, ttvn, tt_crc,
 
1879
                                        full_table);
 
1880
                        return;
 
1881
                }
 
1882
        }
 
1883
}