Blame view

net/batman-adv/vis.c 24.8 KB
c6c8fea29   Sven Eckelmann   net: Add batman-a...
1
  /*
64afe3539   Sven Eckelmann   batman-adv: Updat...
2
   * Copyright (C) 2008-2011 B.A.T.M.A.N. contributors:
c6c8fea29   Sven Eckelmann   net: Add batman-a...
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
   *
   * Simon Wunderlich
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of version 2 of the GNU General Public
   * License as published by the Free Software Foundation.
   *
   * This program is distributed in the hope that it will be useful, but
   * WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   * General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
   * 02110-1301, USA
   *
   */
  
  #include "main.h"
  #include "send.h"
  #include "translation-table.h"
  #include "vis.h"
  #include "soft-interface.h"
  #include "hard-interface.h"
  #include "hash.h"
  #include "originator.h"
  
  #define MAX_VIS_PACKET_SIZE 1000
c6c8fea29   Sven Eckelmann   net: Add batman-a...
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
  static void start_vis_timer(struct bat_priv *bat_priv);
  
  /* free the info */
  static void free_info(struct kref *ref)
  {
  	struct vis_info *info = container_of(ref, struct vis_info, refcount);
  	struct bat_priv *bat_priv = info->bat_priv;
  	struct recvlist_node *entry, *tmp;
  
  	list_del_init(&info->send_list);
  	spin_lock_bh(&bat_priv->vis_list_lock);
  	list_for_each_entry_safe(entry, tmp, &info->recv_list, list) {
  		list_del(&entry->list);
  		kfree(entry);
  	}
  
  	spin_unlock_bh(&bat_priv->vis_list_lock);
  	kfree_skb(info->skb_packet);
dda9fc6b2   Sven Eckelmann   batman-adv: Remov...
50
  	kfree(info);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
51
52
53
  }
  
  /* Compare two vis packets, used by the hashing algorithm */
747e4221a   Sven Eckelmann   batman-adv: Add c...
54
  static int vis_info_cmp(const struct hlist_node *node, const void *data2)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
55
  {
747e4221a   Sven Eckelmann   batman-adv: Add c...
56
57
  	const struct vis_info *d1, *d2;
  	const struct vis_packet *p1, *p2;
7aadf889e   Marek Lindner   batman-adv: remov...
58
59
  
  	d1 = container_of(node, struct vis_info, hash_entry);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
60
61
62
  	d2 = data2;
  	p1 = (struct vis_packet *)d1->skb_packet->data;
  	p2 = (struct vis_packet *)d2->skb_packet->data;
39901e716   Marek Lindner   batman-adv: separ...
63
  	return compare_eth(p1->vis_orig, p2->vis_orig);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
64
65
66
67
  }
  
  /* hash function to choose an entry in a hash table of given size */
  /* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */
c90681b85   Antonio Quartulli   batman-adv: fixed...
68
  static uint32_t vis_info_choose(const void *data, uint32_t size)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
69
  {
747e4221a   Sven Eckelmann   batman-adv: Add c...
70
71
72
  	const struct vis_info *vis_info = data;
  	const struct vis_packet *packet;
  	const unsigned char *key;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
  	uint32_t hash = 0;
  	size_t i;
  
  	packet = (struct vis_packet *)vis_info->skb_packet->data;
  	key = packet->vis_orig;
  	for (i = 0; i < ETH_ALEN; i++) {
  		hash += key[i];
  		hash += (hash << 10);
  		hash ^= (hash >> 6);
  	}
  
  	hash += (hash << 3);
  	hash ^= (hash >> 11);
  	hash += (hash << 15);
  
  	return hash % size;
  }
7aadf889e   Marek Lindner   batman-adv: remov...
90
  static struct vis_info *vis_hash_find(struct bat_priv *bat_priv,
747e4221a   Sven Eckelmann   batman-adv: Add c...
91
  				      const void *data)
7aadf889e   Marek Lindner   batman-adv: remov...
92
93
94
95
96
  {
  	struct hashtable_t *hash = bat_priv->vis_hash;
  	struct hlist_head *head;
  	struct hlist_node *node;
  	struct vis_info *vis_info, *vis_info_tmp = NULL;
c90681b85   Antonio Quartulli   batman-adv: fixed...
97
  	uint32_t index;
7aadf889e   Marek Lindner   batman-adv: remov...
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
  
  	if (!hash)
  		return NULL;
  
  	index = vis_info_choose(data, hash->size);
  	head = &hash->table[index];
  
  	rcu_read_lock();
  	hlist_for_each_entry_rcu(vis_info, node, head, hash_entry) {
  		if (!vis_info_cmp(node, data))
  			continue;
  
  		vis_info_tmp = vis_info;
  		break;
  	}
  	rcu_read_unlock();
  
  	return vis_info_tmp;
  }
c6c8fea29   Sven Eckelmann   net: Add batman-a...
117
118
119
120
121
122
123
124
125
126
  /* insert interface to the list of interfaces of one originator, if it
   * does not already exist in the list */
  static void vis_data_insert_interface(const uint8_t *interface,
  				      struct hlist_head *if_list,
  				      bool primary)
  {
  	struct if_list_entry *entry;
  	struct hlist_node *pos;
  
  	hlist_for_each_entry(entry, pos, if_list, list) {
747e4221a   Sven Eckelmann   batman-adv: Add c...
127
  		if (compare_eth(entry->addr, interface))
c6c8fea29   Sven Eckelmann   net: Add batman-a...
128
129
  			return;
  	}
015758d00   Antonio Quartulli   batman-adv: corre...
130
  	/* it's a new address, add it to the list */
c6c8fea29   Sven Eckelmann   net: Add batman-a...
131
132
133
134
135
136
137
  	entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
  	if (!entry)
  		return;
  	memcpy(entry->addr, interface, ETH_ALEN);
  	entry->primary = primary;
  	hlist_add_head(&entry->list, if_list);
  }
747e4221a   Sven Eckelmann   batman-adv: Add c...
138
139
  static ssize_t vis_data_read_prim_sec(char *buff,
  				      const struct hlist_head *if_list)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
  {
  	struct if_list_entry *entry;
  	struct hlist_node *pos;
  	size_t len = 0;
  
  	hlist_for_each_entry(entry, pos, if_list, list) {
  		if (entry->primary)
  			len += sprintf(buff + len, "PRIMARY, ");
  		else
  			len += sprintf(buff + len,  "SEC %pM, ", entry->addr);
  	}
  
  	return len;
  }
  
  static size_t vis_data_count_prim_sec(struct hlist_head *if_list)
  {
  	struct if_list_entry *entry;
  	struct hlist_node *pos;
  	size_t count = 0;
  
  	hlist_for_each_entry(entry, pos, if_list, list) {
  		if (entry->primary)
  			count += 9;
  		else
  			count += 23;
  	}
  
  	return count;
  }
  
  /* read an entry  */
747e4221a   Sven Eckelmann   batman-adv: Add c...
172
173
174
  static ssize_t vis_data_read_entry(char *buff,
  				   const struct vis_info_entry *entry,
  				   const uint8_t *src, bool primary)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
175
176
177
  {
  	/* maximal length: max(4+17+2, 3+17+1+3+2) == 26 */
  	if (primary && entry->quality == 0)
2dafb49d8   Antonio Quartulli   batman-adv: renam...
178
  		return sprintf(buff, "TT %pM, ", entry->dest);
39901e716   Marek Lindner   batman-adv: separ...
179
  	else if (compare_eth(entry->src, src))
c6c8fea29   Sven Eckelmann   net: Add batman-a...
180
181
182
183
184
185
186
187
  		return sprintf(buff, "TQ %pM %d, ", entry->dest,
  			       entry->quality);
  
  	return 0;
  }
  
  int vis_seq_print_text(struct seq_file *seq, void *offset)
  {
32ae9b221   Marek Lindner   batman-adv: Make ...
188
  	struct hard_iface *primary_if;
7aadf889e   Marek Lindner   batman-adv: remov...
189
  	struct hlist_node *node;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
190
  	struct hlist_head *head;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
191
192
193
194
195
196
197
198
199
  	struct vis_info *info;
  	struct vis_packet *packet;
  	struct vis_info_entry *entries;
  	struct net_device *net_dev = (struct net_device *)seq->private;
  	struct bat_priv *bat_priv = netdev_priv(net_dev);
  	struct hashtable_t *hash = bat_priv->vis_hash;
  	HLIST_HEAD(vis_if_list);
  	struct if_list_entry *entry;
  	struct hlist_node *pos, *n;
c90681b85   Antonio Quartulli   batman-adv: fixed...
200
201
  	uint32_t i;
  	int j, ret = 0;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
202
203
204
205
  	int vis_server = atomic_read(&bat_priv->vis_mode);
  	size_t buff_pos, buf_size;
  	char *buff;
  	int compare;
32ae9b221   Marek Lindner   batman-adv: Make ...
206
207
208
209
210
211
  	primary_if = primary_if_get_selected(bat_priv);
  	if (!primary_if)
  		goto out;
  
  	if (vis_server == VIS_TYPE_CLIENT_UPDATE)
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
212
213
214
215
216
217
  
  	buf_size = 1;
  	/* Estimate length */
  	spin_lock_bh(&bat_priv->vis_hash_lock);
  	for (i = 0; i < hash->size; i++) {
  		head = &hash->table[i];
7aadf889e   Marek Lindner   batman-adv: remov...
218
219
  		rcu_read_lock();
  		hlist_for_each_entry_rcu(info, node, head, hash_entry) {
c6c8fea29   Sven Eckelmann   net: Add batman-a...
220
221
  			packet = (struct vis_packet *)info->skb_packet->data;
  			entries = (struct vis_info_entry *)
704509b8d   Sven Eckelmann   batman-adv: Calcu...
222
  				((char *)packet + sizeof(*packet));
c6c8fea29   Sven Eckelmann   net: Add batman-a...
223
224
225
226
227
  
  			for (j = 0; j < packet->entries; j++) {
  				if (entries[j].quality == 0)
  					continue;
  				compare =
39901e716   Marek Lindner   batman-adv: separ...
228
  				 compare_eth(entries[j].src, packet->vis_orig);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
229
230
231
232
233
234
235
236
237
  				vis_data_insert_interface(entries[j].src,
  							  &vis_if_list,
  							  compare);
  			}
  
  			hlist_for_each_entry(entry, pos, &vis_if_list, list) {
  				buf_size += 18 + 26 * packet->entries;
  
  				/* add primary/secondary records */
39901e716   Marek Lindner   batman-adv: separ...
238
  				if (compare_eth(entry->addr, packet->vis_orig))
c6c8fea29   Sven Eckelmann   net: Add batman-a...
239
240
241
242
243
244
245
246
247
248
249
250
  					buf_size +=
  					  vis_data_count_prim_sec(&vis_if_list);
  
  				buf_size += 1;
  			}
  
  			hlist_for_each_entry_safe(entry, pos, n, &vis_if_list,
  						  list) {
  				hlist_del(&entry->list);
  				kfree(entry);
  			}
  		}
7aadf889e   Marek Lindner   batman-adv: remov...
251
  		rcu_read_unlock();
c6c8fea29   Sven Eckelmann   net: Add batman-a...
252
253
254
255
256
  	}
  
  	buff = kmalloc(buf_size, GFP_ATOMIC);
  	if (!buff) {
  		spin_unlock_bh(&bat_priv->vis_hash_lock);
32ae9b221   Marek Lindner   batman-adv: Make ...
257
258
  		ret = -ENOMEM;
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
259
260
261
262
263
264
  	}
  	buff[0] = '\0';
  	buff_pos = 0;
  
  	for (i = 0; i < hash->size; i++) {
  		head = &hash->table[i];
7aadf889e   Marek Lindner   batman-adv: remov...
265
266
  		rcu_read_lock();
  		hlist_for_each_entry_rcu(info, node, head, hash_entry) {
c6c8fea29   Sven Eckelmann   net: Add batman-a...
267
268
  			packet = (struct vis_packet *)info->skb_packet->data;
  			entries = (struct vis_info_entry *)
704509b8d   Sven Eckelmann   batman-adv: Calcu...
269
  				((char *)packet + sizeof(*packet));
c6c8fea29   Sven Eckelmann   net: Add batman-a...
270
271
272
273
274
  
  			for (j = 0; j < packet->entries; j++) {
  				if (entries[j].quality == 0)
  					continue;
  				compare =
39901e716   Marek Lindner   batman-adv: separ...
275
  				 compare_eth(entries[j].src, packet->vis_orig);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
276
277
278
279
280
281
282
283
  				vis_data_insert_interface(entries[j].src,
  							  &vis_if_list,
  							  compare);
  			}
  
  			hlist_for_each_entry(entry, pos, &vis_if_list, list) {
  				buff_pos += sprintf(buff + buff_pos, "%pM,",
  						entry->addr);
dd58ddc69   Linus Lüssing   batman-adv: Fix k...
284
  				for (j = 0; j < packet->entries; j++)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
285
286
  					buff_pos += vis_data_read_entry(
  							buff + buff_pos,
dd58ddc69   Linus Lüssing   batman-adv: Fix k...
287
  							&entries[j],
c6c8fea29   Sven Eckelmann   net: Add batman-a...
288
289
290
291
  							entry->addr,
  							entry->primary);
  
  				/* add primary/secondary records */
39901e716   Marek Lindner   batman-adv: separ...
292
  				if (compare_eth(entry->addr, packet->vis_orig))
c6c8fea29   Sven Eckelmann   net: Add batman-a...
293
294
295
296
297
298
299
300
301
302
303
304
305
306
  					buff_pos +=
  					 vis_data_read_prim_sec(buff + buff_pos,
  								&vis_if_list);
  
  				buff_pos += sprintf(buff + buff_pos, "
  ");
  			}
  
  			hlist_for_each_entry_safe(entry, pos, n, &vis_if_list,
  						  list) {
  				hlist_del(&entry->list);
  				kfree(entry);
  			}
  		}
7aadf889e   Marek Lindner   batman-adv: remov...
307
  		rcu_read_unlock();
c6c8fea29   Sven Eckelmann   net: Add batman-a...
308
309
310
311
312
313
  	}
  
  	spin_unlock_bh(&bat_priv->vis_hash_lock);
  
  	seq_printf(seq, "%s", buff);
  	kfree(buff);
32ae9b221   Marek Lindner   batman-adv: Make ...
314
315
316
317
  out:
  	if (primary_if)
  		hardif_free_ref(primary_if);
  	return ret;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
  }
  
  /* add the info packet to the send list, if it was not
   * already linked in. */
  static void send_list_add(struct bat_priv *bat_priv, struct vis_info *info)
  {
  	if (list_empty(&info->send_list)) {
  		kref_get(&info->refcount);
  		list_add_tail(&info->send_list, &bat_priv->vis_send_list);
  	}
  }
  
  /* delete the info packet from the send list, if it was
   * linked in. */
  static void send_list_del(struct vis_info *info)
  {
  	if (!list_empty(&info->send_list)) {
  		list_del_init(&info->send_list);
  		kref_put(&info->refcount, free_info);
  	}
  }
  
  /* tries to add one entry to the receive list. */
  static void recv_list_add(struct bat_priv *bat_priv,
747e4221a   Sven Eckelmann   batman-adv: Add c...
342
  			  struct list_head *recv_list, const char *mac)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
343
344
  {
  	struct recvlist_node *entry;
704509b8d   Sven Eckelmann   batman-adv: Calcu...
345
  	entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
346
347
348
349
350
351
352
353
354
355
356
  	if (!entry)
  		return;
  
  	memcpy(entry->mac, mac, ETH_ALEN);
  	spin_lock_bh(&bat_priv->vis_list_lock);
  	list_add_tail(&entry->list, recv_list);
  	spin_unlock_bh(&bat_priv->vis_list_lock);
  }
  
  /* returns 1 if this mac is in the recv_list */
  static int recv_list_is_in(struct bat_priv *bat_priv,
747e4221a   Sven Eckelmann   batman-adv: Add c...
357
  			   const struct list_head *recv_list, const char *mac)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
358
  {
747e4221a   Sven Eckelmann   batman-adv: Add c...
359
  	const struct recvlist_node *entry;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
360
361
362
  
  	spin_lock_bh(&bat_priv->vis_list_lock);
  	list_for_each_entry(entry, recv_list, list) {
39901e716   Marek Lindner   batman-adv: separ...
363
  		if (compare_eth(entry->mac, mac)) {
c6c8fea29   Sven Eckelmann   net: Add batman-a...
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
  			spin_unlock_bh(&bat_priv->vis_list_lock);
  			return 1;
  		}
  	}
  	spin_unlock_bh(&bat_priv->vis_list_lock);
  	return 0;
  }
  
  /* try to add the packet to the vis_hash. return NULL if invalid (e.g. too old,
   * broken.. ).	vis hash must be locked outside.  is_new is set when the packet
   * is newer than old entries in the hash. */
  static struct vis_info *add_packet(struct bat_priv *bat_priv,
  				   struct vis_packet *vis_packet,
  				   int vis_info_len, int *is_new,
  				   int make_broadcast)
  {
  	struct vis_info *info, *old_info;
  	struct vis_packet *search_packet, *old_packet;
  	struct vis_info search_elem;
  	struct vis_packet *packet;
  	int hash_added;
  
  	*is_new = 0;
  	/* sanity check */
  	if (!bat_priv->vis_hash)
  		return NULL;
  
  	/* see if the packet is already in vis_hash */
704509b8d   Sven Eckelmann   batman-adv: Calcu...
392
  	search_elem.skb_packet = dev_alloc_skb(sizeof(*search_packet));
c6c8fea29   Sven Eckelmann   net: Add batman-a...
393
394
395
  	if (!search_elem.skb_packet)
  		return NULL;
  	search_packet = (struct vis_packet *)skb_put(search_elem.skb_packet,
704509b8d   Sven Eckelmann   batman-adv: Calcu...
396
  						     sizeof(*search_packet));
c6c8fea29   Sven Eckelmann   net: Add batman-a...
397
398
  
  	memcpy(search_packet->vis_orig, vis_packet->vis_orig, ETH_ALEN);
7aadf889e   Marek Lindner   batman-adv: remov...
399
  	old_info = vis_hash_find(bat_priv, &search_elem);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
  	kfree_skb(search_elem.skb_packet);
  
  	if (old_info) {
  		old_packet = (struct vis_packet *)old_info->skb_packet->data;
  		if (!seq_after(ntohl(vis_packet->seqno),
  			       ntohl(old_packet->seqno))) {
  			if (old_packet->seqno == vis_packet->seqno) {
  				recv_list_add(bat_priv, &old_info->recv_list,
  					      vis_packet->sender_orig);
  				return old_info;
  			} else {
  				/* newer packet is already in hash. */
  				return NULL;
  			}
  		}
  		/* remove old entry */
  		hash_remove(bat_priv->vis_hash, vis_info_cmp, vis_info_choose,
  			    old_info);
  		send_list_del(old_info);
  		kref_put(&old_info->refcount, free_info);
  	}
704509b8d   Sven Eckelmann   batman-adv: Calcu...
421
  	info = kmalloc(sizeof(*info), GFP_ATOMIC);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
422
423
  	if (!info)
  		return NULL;
704509b8d   Sven Eckelmann   batman-adv: Calcu...
424
425
  	info->skb_packet = dev_alloc_skb(sizeof(*packet) + vis_info_len +
  					 sizeof(struct ethhdr));
c6c8fea29   Sven Eckelmann   net: Add batman-a...
426
427
428
429
430
  	if (!info->skb_packet) {
  		kfree(info);
  		return NULL;
  	}
  	skb_reserve(info->skb_packet, sizeof(struct ethhdr));
704509b8d   Sven Eckelmann   batman-adv: Calcu...
431
432
  	packet = (struct vis_packet *)skb_put(info->skb_packet, sizeof(*packet)
  					      + vis_info_len);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
433
434
435
436
437
438
  
  	kref_init(&info->refcount);
  	INIT_LIST_HEAD(&info->send_list);
  	INIT_LIST_HEAD(&info->recv_list);
  	info->first_seen = jiffies;
  	info->bat_priv = bat_priv;
704509b8d   Sven Eckelmann   batman-adv: Calcu...
439
  	memcpy(packet, vis_packet, sizeof(*packet) + vis_info_len);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
  
  	/* initialize and add new packet. */
  	*is_new = 1;
  
  	/* Make it a broadcast packet, if required */
  	if (make_broadcast)
  		memcpy(packet->target_orig, broadcast_addr, ETH_ALEN);
  
  	/* repair if entries is longer than packet. */
  	if (packet->entries * sizeof(struct vis_info_entry) > vis_info_len)
  		packet->entries = vis_info_len / sizeof(struct vis_info_entry);
  
  	recv_list_add(bat_priv, &info->recv_list, packet->sender_orig);
  
  	/* try to add it */
  	hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose,
7aadf889e   Marek Lindner   batman-adv: remov...
456
  			      info, &info->hash_entry);
1a1f37d92   Antonio Quartulli   batman-adv: hash_...
457
  	if (hash_added != 0) {
c6c8fea29   Sven Eckelmann   net: Add batman-a...
458
  		/* did not work (for some reason) */
2674c1587   Sven Eckelmann   batman-adv: Remov...
459
  		kref_put(&info->refcount, free_info);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
  		info = NULL;
  	}
  
  	return info;
  }
  
  /* handle the server sync packet, forward if needed. */
  void receive_server_sync_packet(struct bat_priv *bat_priv,
  				struct vis_packet *vis_packet,
  				int vis_info_len)
  {
  	struct vis_info *info;
  	int is_new, make_broadcast;
  	int vis_server = atomic_read(&bat_priv->vis_mode);
  
  	make_broadcast = (vis_server == VIS_TYPE_SERVER_SYNC);
  
  	spin_lock_bh(&bat_priv->vis_hash_lock);
  	info = add_packet(bat_priv, vis_packet, vis_info_len,
  			  &is_new, make_broadcast);
  	if (!info)
  		goto end;
  
  	/* only if we are server ourselves and packet is newer than the one in
  	 * hash.*/
  	if (vis_server == VIS_TYPE_SERVER_SYNC && is_new)
  		send_list_add(bat_priv, info);
  end:
  	spin_unlock_bh(&bat_priv->vis_hash_lock);
  }
  
  /* handle an incoming client update packet and schedule forward if needed. */
  void receive_client_update_packet(struct bat_priv *bat_priv,
  				  struct vis_packet *vis_packet,
  				  int vis_info_len)
  {
  	struct vis_info *info;
  	struct vis_packet *packet;
  	int is_new;
  	int vis_server = atomic_read(&bat_priv->vis_mode);
  	int are_target = 0;
  
  	/* clients shall not broadcast. */
  	if (is_broadcast_ether_addr(vis_packet->target_orig))
  		return;
  
  	/* Are we the target for this VIS packet? */
  	if (vis_server == VIS_TYPE_SERVER_SYNC	&&
  	    is_my_mac(vis_packet->target_orig))
  		are_target = 1;
  
  	spin_lock_bh(&bat_priv->vis_hash_lock);
  	info = add_packet(bat_priv, vis_packet, vis_info_len,
  			  &is_new, are_target);
  
  	if (!info)
  		goto end;
  	/* note that outdated packets will be dropped at this point. */
  
  	packet = (struct vis_packet *)info->skb_packet->data;
  
  	/* send only if we're the target server or ... */
  	if (are_target && is_new) {
  		packet->vis_type = VIS_TYPE_SERVER_SYNC;	/* upgrade! */
  		send_list_add(bat_priv, info);
  
  		/* ... we're not the recipient (and thus need to forward). */
  	} else if (!is_my_mac(packet->target_orig)) {
  		send_list_add(bat_priv, info);
  	}
  
  end:
  	spin_unlock_bh(&bat_priv->vis_hash_lock);
  }
  
  /* Walk the originators and find the VIS server with the best tq. Set the packet
   * address to its address and return the best_tq.
   *
   * Must be called with the originator hash locked */
  static int find_best_vis_server(struct bat_priv *bat_priv,
  				struct vis_info *info)
  {
  	struct hashtable_t *hash = bat_priv->orig_hash;
e1a5382f9   Linus Lüssing   batman-adv: Make ...
543
  	struct neigh_node *router;
7aadf889e   Marek Lindner   batman-adv: remov...
544
  	struct hlist_node *node;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
545
  	struct hlist_head *head;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
546
547
  	struct orig_node *orig_node;
  	struct vis_packet *packet;
c90681b85   Antonio Quartulli   batman-adv: fixed...
548
549
  	int best_tq = -1;
  	uint32_t i;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
550
551
552
553
554
  
  	packet = (struct vis_packet *)info->skb_packet->data;
  
  	for (i = 0; i < hash->size; i++) {
  		head = &hash->table[i];
fb778ea17   Marek Lindner   batman-adv: prote...
555
  		rcu_read_lock();
7aadf889e   Marek Lindner   batman-adv: remov...
556
  		hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) {
e1a5382f9   Linus Lüssing   batman-adv: Make ...
557
558
559
560
561
562
563
  			router = orig_node_get_router(orig_node);
  			if (!router)
  				continue;
  
  			if ((orig_node->flags & VIS_SERVER) &&
  			    (router->tq_avg > best_tq)) {
  				best_tq = router->tq_avg;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
564
565
566
  				memcpy(packet->target_orig, orig_node->orig,
  				       ETH_ALEN);
  			}
e1a5382f9   Linus Lüssing   batman-adv: Make ...
567
  			neigh_node_free_ref(router);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
568
  		}
fb778ea17   Marek Lindner   batman-adv: prote...
569
  		rcu_read_unlock();
c6c8fea29   Sven Eckelmann   net: Add batman-a...
570
571
572
573
574
575
  	}
  
  	return best_tq;
  }
  
  /* Return true if the vis packet is full. */
747e4221a   Sven Eckelmann   batman-adv: Add c...
576
  static bool vis_packet_full(const struct vis_info *info)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
577
  {
747e4221a   Sven Eckelmann   batman-adv: Add c...
578
  	const struct vis_packet *packet;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
579
580
581
582
583
584
585
586
587
588
589
590
591
  	packet = (struct vis_packet *)info->skb_packet->data;
  
  	if (MAX_VIS_PACKET_SIZE / sizeof(struct vis_info_entry)
  		< packet->entries + 1)
  		return true;
  	return false;
  }
  
  /* generates a packet of own vis data,
   * returns 0 on success, -1 if no packet could be generated */
  static int generate_vis_packet(struct bat_priv *bat_priv)
  {
  	struct hashtable_t *hash = bat_priv->orig_hash;
7aadf889e   Marek Lindner   batman-adv: remov...
592
  	struct hlist_node *node;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
593
  	struct hlist_head *head;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
594
  	struct orig_node *orig_node;
e1a5382f9   Linus Lüssing   batman-adv: Make ...
595
  	struct neigh_node *router;
958ca5985   Sven Eckelmann   batman-adv: Remov...
596
  	struct vis_info *info = bat_priv->my_vis_info;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
597
598
  	struct vis_packet *packet = (struct vis_packet *)info->skb_packet->data;
  	struct vis_info_entry *entry;
48100bac8   Antonio Quartulli   batman-adv: creat...
599
  	struct tt_common_entry *tt_common_entry;
c90681b85   Antonio Quartulli   batman-adv: fixed...
600
601
  	int best_tq = -1;
  	uint32_t i;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
602
603
604
  
  	info->first_seen = jiffies;
  	packet->vis_type = atomic_read(&bat_priv->vis_mode);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
605
606
607
608
  	memcpy(packet->target_orig, broadcast_addr, ETH_ALEN);
  	packet->ttl = TTL;
  	packet->seqno = htonl(ntohl(packet->seqno) + 1);
  	packet->entries = 0;
704509b8d   Sven Eckelmann   batman-adv: Calcu...
609
  	skb_trim(info->skb_packet, sizeof(*packet));
c6c8fea29   Sven Eckelmann   net: Add batman-a...
610
611
612
  
  	if (packet->vis_type == VIS_TYPE_CLIENT_UPDATE) {
  		best_tq = find_best_vis_server(bat_priv, info);
d0072609b   Marek Lindner   batman-adv: remov...
613
  		if (best_tq < 0)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
614
  			return -1;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
615
616
617
618
  	}
  
  	for (i = 0; i < hash->size; i++) {
  		head = &hash->table[i];
fb778ea17   Marek Lindner   batman-adv: prote...
619
  		rcu_read_lock();
7aadf889e   Marek Lindner   batman-adv: remov...
620
  		hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) {
e1a5382f9   Linus Lüssing   batman-adv: Make ...
621
622
  			router = orig_node_get_router(orig_node);
  			if (!router)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
623
  				continue;
e1a5382f9   Linus Lüssing   batman-adv: Make ...
624
625
  			if (!compare_eth(router->addr, orig_node->orig))
  				goto next;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
626

e1a5382f9   Linus Lüssing   batman-adv: Make ...
627
628
  			if (router->if_incoming->if_status != IF_ACTIVE)
  				goto next;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
629

e1a5382f9   Linus Lüssing   batman-adv: Make ...
630
631
  			if (router->tq_avg < 1)
  				goto next;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
632
633
634
635
636
  
  			/* fill one entry into buffer. */
  			entry = (struct vis_info_entry *)
  				      skb_put(info->skb_packet, sizeof(*entry));
  			memcpy(entry->src,
e1a5382f9   Linus Lüssing   batman-adv: Make ...
637
  			       router->if_incoming->net_dev->dev_addr,
c6c8fea29   Sven Eckelmann   net: Add batman-a...
638
639
  			       ETH_ALEN);
  			memcpy(entry->dest, orig_node->orig, ETH_ALEN);
e1a5382f9   Linus Lüssing   batman-adv: Make ...
640
  			entry->quality = router->tq_avg;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
641
  			packet->entries++;
e1a5382f9   Linus Lüssing   batman-adv: Make ...
642
643
  next:
  			neigh_node_free_ref(router);
d0072609b   Marek Lindner   batman-adv: remov...
644
645
  			if (vis_packet_full(info))
  				goto unlock;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
646
  		}
fb778ea17   Marek Lindner   batman-adv: prote...
647
  		rcu_read_unlock();
c6c8fea29   Sven Eckelmann   net: Add batman-a...
648
  	}
2dafb49d8   Antonio Quartulli   batman-adv: renam...
649
  	hash = bat_priv->tt_local_hash;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
650

c6c8fea29   Sven Eckelmann   net: Add batman-a...
651
652
  	for (i = 0; i < hash->size; i++) {
  		head = &hash->table[i];
7683fdc1e   Antonio Quartulli   batman-adv: prote...
653
  		rcu_read_lock();
48100bac8   Antonio Quartulli   batman-adv: creat...
654
  		hlist_for_each_entry_rcu(tt_common_entry, node, head,
7683fdc1e   Antonio Quartulli   batman-adv: prote...
655
  					 hash_entry) {
c6c8fea29   Sven Eckelmann   net: Add batman-a...
656
657
658
659
  			entry = (struct vis_info_entry *)
  					skb_put(info->skb_packet,
  						sizeof(*entry));
  			memset(entry->src, 0, ETH_ALEN);
48100bac8   Antonio Quartulli   batman-adv: creat...
660
  			memcpy(entry->dest, tt_common_entry->addr, ETH_ALEN);
2dafb49d8   Antonio Quartulli   batman-adv: renam...
661
  			entry->quality = 0; /* 0 means TT */
c6c8fea29   Sven Eckelmann   net: Add batman-a...
662
  			packet->entries++;
7683fdc1e   Antonio Quartulli   batman-adv: prote...
663
664
  			if (vis_packet_full(info))
  				goto unlock;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
665
  		}
7683fdc1e   Antonio Quartulli   batman-adv: prote...
666
  		rcu_read_unlock();
c6c8fea29   Sven Eckelmann   net: Add batman-a...
667
  	}
c6c8fea29   Sven Eckelmann   net: Add batman-a...
668
  	return 0;
d0072609b   Marek Lindner   batman-adv: remov...
669
670
671
672
  
  unlock:
  	rcu_read_unlock();
  	return 0;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
673
674
675
676
677
678
  }
  
  /* free old vis packets. Must be called with this vis_hash_lock
   * held */
  static void purge_vis_packets(struct bat_priv *bat_priv)
  {
c90681b85   Antonio Quartulli   batman-adv: fixed...
679
  	uint32_t i;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
680
  	struct hashtable_t *hash = bat_priv->vis_hash;
7aadf889e   Marek Lindner   batman-adv: remov...
681
  	struct hlist_node *node, *node_tmp;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
682
  	struct hlist_head *head;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
683
684
685
686
  	struct vis_info *info;
  
  	for (i = 0; i < hash->size; i++) {
  		head = &hash->table[i];
7aadf889e   Marek Lindner   batman-adv: remov...
687
688
  		hlist_for_each_entry_safe(info, node, node_tmp,
  					  head, hash_entry) {
c6c8fea29   Sven Eckelmann   net: Add batman-a...
689
690
691
692
693
694
  			/* never purge own data. */
  			if (info == bat_priv->my_vis_info)
  				continue;
  
  			if (time_after(jiffies,
  				       info->first_seen + VIS_TIMEOUT * HZ)) {
7aadf889e   Marek Lindner   batman-adv: remov...
695
  				hlist_del(node);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
696
697
698
699
700
701
702
703
704
705
  				send_list_del(info);
  				kref_put(&info->refcount, free_info);
  			}
  		}
  	}
  }
  
  static void broadcast_vis_packet(struct bat_priv *bat_priv,
  				 struct vis_info *info)
  {
e1a5382f9   Linus Lüssing   batman-adv: Make ...
706
  	struct neigh_node *router;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
707
  	struct hashtable_t *hash = bat_priv->orig_hash;
7aadf889e   Marek Lindner   batman-adv: remov...
708
  	struct hlist_node *node;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
709
  	struct hlist_head *head;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
710
711
712
  	struct orig_node *orig_node;
  	struct vis_packet *packet;
  	struct sk_buff *skb;
e6c10f433   Marek Lindner   batman-adv: renam...
713
  	struct hard_iface *hard_iface;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
714
  	uint8_t dstaddr[ETH_ALEN];
c90681b85   Antonio Quartulli   batman-adv: fixed...
715
  	uint32_t i;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
716

c6c8fea29   Sven Eckelmann   net: Add batman-a...
717
718
719
720
721
  	packet = (struct vis_packet *)info->skb_packet->data;
  
  	/* send to all routers in range. */
  	for (i = 0; i < hash->size; i++) {
  		head = &hash->table[i];
fb778ea17   Marek Lindner   batman-adv: prote...
722
  		rcu_read_lock();
7aadf889e   Marek Lindner   batman-adv: remov...
723
  		hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) {
c6c8fea29   Sven Eckelmann   net: Add batman-a...
724
  			/* if it's a vis server and reachable, send it. */
c6c8fea29   Sven Eckelmann   net: Add batman-a...
725
726
  			if (!(orig_node->flags & VIS_SERVER))
  				continue;
e1a5382f9   Linus Lüssing   batman-adv: Make ...
727
728
729
730
  
  			router = orig_node_get_router(orig_node);
  			if (!router)
  				continue;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
731
  			/* don't send it if we already received the packet from
e1a5382f9   Linus Lüssing   batman-adv: Make ...
732
  			 * this node. */
c6c8fea29   Sven Eckelmann   net: Add batman-a...
733
  			if (recv_list_is_in(bat_priv, &info->recv_list,
e1a5382f9   Linus Lüssing   batman-adv: Make ...
734
735
  					    orig_node->orig)) {
  				neigh_node_free_ref(router);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
736
  				continue;
e1a5382f9   Linus Lüssing   batman-adv: Make ...
737
  			}
c6c8fea29   Sven Eckelmann   net: Add batman-a...
738
739
  
  			memcpy(packet->target_orig, orig_node->orig, ETH_ALEN);
e1a5382f9   Linus Lüssing   batman-adv: Make ...
740
741
742
743
  			hard_iface = router->if_incoming;
  			memcpy(dstaddr, router->addr, ETH_ALEN);
  
  			neigh_node_free_ref(router);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
744
745
746
  
  			skb = skb_clone(info->skb_packet, GFP_ATOMIC);
  			if (skb)
e6c10f433   Marek Lindner   batman-adv: renam...
747
  				send_skb_packet(skb, hard_iface, dstaddr);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
748

c6c8fea29   Sven Eckelmann   net: Add batman-a...
749
  		}
fb778ea17   Marek Lindner   batman-adv: prote...
750
  		rcu_read_unlock();
c6c8fea29   Sven Eckelmann   net: Add batman-a...
751
  	}
c6c8fea29   Sven Eckelmann   net: Add batman-a...
752
753
754
755
756
757
  }
  
  static void unicast_vis_packet(struct bat_priv *bat_priv,
  			       struct vis_info *info)
  {
  	struct orig_node *orig_node;
e1a5382f9   Linus Lüssing   batman-adv: Make ...
758
  	struct neigh_node *router = NULL;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
759
760
  	struct sk_buff *skb;
  	struct vis_packet *packet;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
761

c6c8fea29   Sven Eckelmann   net: Add batman-a...
762
  	packet = (struct vis_packet *)info->skb_packet->data;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
763

7aadf889e   Marek Lindner   batman-adv: remov...
764
  	orig_node = orig_hash_find(bat_priv, packet->target_orig);
44524fcdf   Marek Lindner   batman-adv: Corre...
765
  	if (!orig_node)
e1a5382f9   Linus Lüssing   batman-adv: Make ...
766
  		goto out;
44524fcdf   Marek Lindner   batman-adv: Corre...
767

e1a5382f9   Linus Lüssing   batman-adv: Make ...
768
769
770
  	router = orig_node_get_router(orig_node);
  	if (!router)
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
771
772
773
  
  	skb = skb_clone(info->skb_packet, GFP_ATOMIC);
  	if (skb)
e1a5382f9   Linus Lüssing   batman-adv: Make ...
774
  		send_skb_packet(skb, router->if_incoming, router->addr);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
775
776
  
  out:
e1a5382f9   Linus Lüssing   batman-adv: Make ...
777
778
  	if (router)
  		neigh_node_free_ref(router);
44524fcdf   Marek Lindner   batman-adv: Corre...
779
  	if (orig_node)
7b36e8eef   Marek Lindner   batman-adv: Corre...
780
  		orig_node_free_ref(orig_node);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
781
782
783
784
785
  }
  
  /* only send one vis packet. called from send_vis_packets() */
  static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info)
  {
32ae9b221   Marek Lindner   batman-adv: Make ...
786
  	struct hard_iface *primary_if;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
787
  	struct vis_packet *packet;
32ae9b221   Marek Lindner   batman-adv: Make ...
788
789
790
  	primary_if = primary_if_get_selected(bat_priv);
  	if (!primary_if)
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
791
792
793
794
  	packet = (struct vis_packet *)info->skb_packet->data;
  	if (packet->ttl < 2) {
  		pr_debug("Error - can't send vis packet: ttl exceeded
  ");
32ae9b221   Marek Lindner   batman-adv: Make ...
795
  		goto out;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
796
  	}
32ae9b221   Marek Lindner   batman-adv: Make ...
797
  	memcpy(packet->sender_orig, primary_if->net_dev->dev_addr, ETH_ALEN);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
798
799
800
801
802
803
804
  	packet->ttl--;
  
  	if (is_broadcast_ether_addr(packet->target_orig))
  		broadcast_vis_packet(bat_priv, info);
  	else
  		unicast_vis_packet(bat_priv, info);
  	packet->ttl++; /* restore TTL */
32ae9b221   Marek Lindner   batman-adv: Make ...
805
806
807
808
  
  out:
  	if (primary_if)
  		hardif_free_ref(primary_if);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
809
810
811
812
813
814
815
816
817
  }
  
  /* called from timer; send (and maybe generate) vis packet. */
  static void send_vis_packets(struct work_struct *work)
  {
  	struct delayed_work *delayed_work =
  		container_of(work, struct delayed_work, work);
  	struct bat_priv *bat_priv =
  		container_of(delayed_work, struct bat_priv, vis_work);
1181e1daa   Sven Eckelmann   batman-adv: Make ...
818
  	struct vis_info *info;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
819
820
821
822
823
824
825
826
  
  	spin_lock_bh(&bat_priv->vis_hash_lock);
  	purge_vis_packets(bat_priv);
  
  	if (generate_vis_packet(bat_priv) == 0) {
  		/* schedule if generation was successful */
  		send_list_add(bat_priv, bat_priv->my_vis_info);
  	}
1181e1daa   Sven Eckelmann   batman-adv: Make ...
827
828
829
  	while (!list_empty(&bat_priv->vis_send_list)) {
  		info = list_first_entry(&bat_priv->vis_send_list,
  					typeof(*info), send_list);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
830
831
832
  
  		kref_get(&info->refcount);
  		spin_unlock_bh(&bat_priv->vis_hash_lock);
32ae9b221   Marek Lindner   batman-adv: Make ...
833
  		send_vis_packet(bat_priv, info);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
  
  		spin_lock_bh(&bat_priv->vis_hash_lock);
  		send_list_del(info);
  		kref_put(&info->refcount, free_info);
  	}
  	spin_unlock_bh(&bat_priv->vis_hash_lock);
  	start_vis_timer(bat_priv);
  }
  
  /* init the vis server. this may only be called when if_list is already
   * initialized (e.g. bat0 is initialized, interfaces have been added) */
  int vis_init(struct bat_priv *bat_priv)
  {
  	struct vis_packet *packet;
  	int hash_added;
  
  	if (bat_priv->vis_hash)
  		return 1;
  
  	spin_lock_bh(&bat_priv->vis_hash_lock);
  
  	bat_priv->vis_hash = hash_new(256);
  	if (!bat_priv->vis_hash) {
  		pr_err("Can't initialize vis_hash
  ");
  		goto err;
  	}
  
  	bat_priv->my_vis_info = kmalloc(MAX_VIS_PACKET_SIZE, GFP_ATOMIC);
320f422f6   Joe Perches   batman-adv: Remov...
863
  	if (!bat_priv->my_vis_info)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
864
  		goto err;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
865

704509b8d   Sven Eckelmann   batman-adv: Calcu...
866
867
868
  	bat_priv->my_vis_info->skb_packet = dev_alloc_skb(sizeof(*packet) +
  							  MAX_VIS_PACKET_SIZE +
  							 sizeof(struct ethhdr));
c6c8fea29   Sven Eckelmann   net: Add batman-a...
869
870
871
872
  	if (!bat_priv->my_vis_info->skb_packet)
  		goto free_info;
  
  	skb_reserve(bat_priv->my_vis_info->skb_packet, sizeof(struct ethhdr));
704509b8d   Sven Eckelmann   batman-adv: Calcu...
873
874
  	packet = (struct vis_packet *)skb_put(bat_priv->my_vis_info->skb_packet,
  					      sizeof(*packet));
c6c8fea29   Sven Eckelmann   net: Add batman-a...
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
  
  	/* prefill the vis info */
  	bat_priv->my_vis_info->first_seen = jiffies -
  						msecs_to_jiffies(VIS_INTERVAL);
  	INIT_LIST_HEAD(&bat_priv->my_vis_info->recv_list);
  	INIT_LIST_HEAD(&bat_priv->my_vis_info->send_list);
  	kref_init(&bat_priv->my_vis_info->refcount);
  	bat_priv->my_vis_info->bat_priv = bat_priv;
  	packet->version = COMPAT_VERSION;
  	packet->packet_type = BAT_VIS;
  	packet->ttl = TTL;
  	packet->seqno = 0;
  	packet->entries = 0;
  
  	INIT_LIST_HEAD(&bat_priv->vis_send_list);
  
  	hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose,
7aadf889e   Marek Lindner   batman-adv: remov...
892
893
  			      bat_priv->my_vis_info,
  			      &bat_priv->my_vis_info->hash_entry);
1a1f37d92   Antonio Quartulli   batman-adv: hash_...
894
  	if (hash_added != 0) {
c6c8fea29   Sven Eckelmann   net: Add batman-a...
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
  		pr_err("Can't add own vis packet into hash
  ");
  		/* not in hash, need to remove it manually. */
  		kref_put(&bat_priv->my_vis_info->refcount, free_info);
  		goto err;
  	}
  
  	spin_unlock_bh(&bat_priv->vis_hash_lock);
  	start_vis_timer(bat_priv);
  	return 1;
  
  free_info:
  	kfree(bat_priv->my_vis_info);
  	bat_priv->my_vis_info = NULL;
  err:
  	spin_unlock_bh(&bat_priv->vis_hash_lock);
  	vis_quit(bat_priv);
  	return 0;
  }
  
  /* Decrease the reference count on a hash item info */
7aadf889e   Marek Lindner   batman-adv: remov...
916
  static void free_info_ref(struct hlist_node *node, void *arg)
c6c8fea29   Sven Eckelmann   net: Add batman-a...
917
  {
7aadf889e   Marek Lindner   batman-adv: remov...
918
  	struct vis_info *info;
c6c8fea29   Sven Eckelmann   net: Add batman-a...
919

7aadf889e   Marek Lindner   batman-adv: remov...
920
  	info = container_of(node, struct vis_info, hash_entry);
c6c8fea29   Sven Eckelmann   net: Add batman-a...
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
  	send_list_del(info);
  	kref_put(&info->refcount, free_info);
  }
  
  /* shutdown vis-server */
  void vis_quit(struct bat_priv *bat_priv)
  {
  	if (!bat_priv->vis_hash)
  		return;
  
  	cancel_delayed_work_sync(&bat_priv->vis_work);
  
  	spin_lock_bh(&bat_priv->vis_hash_lock);
  	/* properly remove, kill timers ... */
  	hash_delete(bat_priv->vis_hash, free_info_ref, NULL);
  	bat_priv->vis_hash = NULL;
  	bat_priv->my_vis_info = NULL;
  	spin_unlock_bh(&bat_priv->vis_hash_lock);
  }
  
  /* schedule packets for (re)transmission */
  static void start_vis_timer(struct bat_priv *bat_priv)
  {
  	INIT_DELAYED_WORK(&bat_priv->vis_work, send_vis_packets);
  	queue_delayed_work(bat_event_workqueue, &bat_priv->vis_work,
  			   msecs_to_jiffies(VIS_INTERVAL));
  }