~ubuntu-branches/ubuntu/trusty/linux-armadaxp/trusty

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Michael Casadevall, Bryan Wu, Dann Frazier, Michael Casadeall
  • Date: 2012-03-10 15:00:54 UTC
  • mfrom: (1.1.1)
  • Revision ID: package-import@ubuntu.com-20120310150054-flugb39zon8vvgwe
Tags: 3.2.0-1600.1
[ Bryan Wu ]
* UBUNTU: import debian/debian.env and debian.armadaxp

[ Dann Frazier ]
* ARM: Armada XP: remove trailing '/' in dirnames in mvRules.mk

[ Michael Casadeall ]
* tools: add some tools for Marvell Armada XP processor
* kernel: timer tick hacking from Marvell
* kernel: Sheeva Errata: add delay on Sheeva when powering down
* net: add Marvell NFP netfilter
* net: socket and skb modifications made by Marvell
* miscdevice: add minor IDs for some Marvell Armada drivers
* fs: introduce memory pool for splice()
* video: EDID detection updates from Marvell Armada XP patchset
* video: backlight: add Marvell Dove LCD backlight driver
* video: display: add THS8200 display driver
* video: framebuffer: add Marvell Dove and Armada XP processor onchip LCD controller driver
* usbtest: add Interrupt transfer testing by Marvell Armada XP code
* usb: ehci: add support for Marvell EHCI controler
* tty/serial: 8250: add support for Marvell Armada XP processor and DeviceTree work
* rtc: add support for Marvell Armada XP onchip RTC controller
* net: pppoe: add Marvell ethernet NFP hook in PPPoE networking driver
* mtd: nand: add support for Marvell Armada XP Nand Flash Controller
* mtd: maps: add Marvell Armada XP specific map driver
* mmc: add support for Marvell Armada XP MMC/SD host controller
* i2c: add support for Marvell Armada XP onchip i2c bus controller
* hwmon: add Kconfig option for Armada XP onchip thermal sensor driver
* dmaengine: add Net DMA support for splice and update Marvell XOR DMA engine driver
* ata: add support for Marvell Armada XP SATA controller and update some quirks
* ARM: add Marvell Armada XP machine to mach-types
* ARM: oprofile: add support for Marvell PJ4B core
* ARM: mm: more ARMv6 switches for Marvell Armada XP
* ARM: remove static declaration to allow compilation
* ARM: alignment access fault trick
* ARM: mm: skip some fault fixing when run on NONE SMP ARMv6 mode during early abort event
* ARM: mm: add Marvell Sheeva CPU Architecture for PJ4B
* ARM: introduce optimized copy operation for Marvell Armada XP
* ARM: SAUCE: hardware breakpoint trick for Marvell Armada XP
* ARM: big endian and little endian tricks for Marvell Armada XP
* ARM: SAUCE: Add Marvell Armada XP build rules to arch/arm/kernel/Makefile
* ARM: vfp: add special handling for Marvell Armada XP
* ARM: add support for Marvell U-Boot
* ARM: add mv_controller_num for ARM PCI drivers
* ARM: add support for local PMUs, general SMP tweaks and cache flushing
* ARM: add Marvell device identifies in glue-proc.h
* ARM: add IPC driver support for Marvell platforms
* ARM: add DMA mapping for Marvell platforms
* ARM: add Sheeva errata and PJ4B code for booting
* ARM: update Kconfig and Makefile to include Marvell Armada XP platforms
* ARM: Armada XP: import LSP from Marvell for Armada XP 3.2 kernel enablement

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